WIP: Animation: operators to update the pose library #104673

Draft
Sybren A. Stüvel wants to merge 10 commits from dr.sybren/blender-addons:pr/poselib-replace-pose into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 69 additions and 1 deletions
Showing only changes of commit 9f89730744 - Show all commits

View File

@ -90,6 +90,8 @@ def pose_library_list_item_context_menu(self: UIList, context: Context) -> None:
with operator_context(layout, 'INVOKE_DEFAULT'):
layout.operator("poselib.blend_pose_asset", text="Blend Pose")
layout.operator("poselib.replace_pose_asset", text="Replace Pose")
layout.separator()
props = layout.operator("poselib.pose_asset_select_bones", text="Select Pose Bones")
props.select = True
@ -147,7 +149,7 @@ class ASSETBROWSER_MT_asset(Menu):
layout.operator("poselib.create_pose_asset").activate_new_action = False
### Messagebus subscription to monitor asset library changes.
# Messagebus subscription to monitor asset library changes.
_msgbus_owner = object()

View File

@ -139,6 +139,71 @@ class POSELIB_OT_create_pose_asset(PoseAssetCreator, Operator):
self.report({'WARNING'}, tip_("Action %s marked Fake User to prevent loss") % action.name)
class POSELIB_OT_replace_pose_asset(Operator):
bl_idname = "poselib.replace_pose_asset"
bl_label = "Replace Pose Asset"
bl_description = (
"Create a new Action that contains the pose of the selected bones, and use that to replace the selected Asset"
)
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context: Context) -> bool:
if not isinstance(getattr(context, "id", None), Action):
return False
if context.object is None or context.object.mode != "POSE":
# The operator assumes pose mode, so that bone selection is visible.
cls.poll_message_set("An active armature object in pose mode is needed")
return False
asset_space_params = asset_browser.params(context.area)
if asset_space_params.asset_library_ref != 'LOCAL':
cls.poll_message_set("Asset Browser must be set to the Current File library")
return False
return True
def execute(self, context: Context) -> Set[str]:
pose_name = context.id.name # This will not use this name entirely, but it'll be made unique.
asset = pose_creation.create_pose_asset_from_context(context, pose_name)
if not asset:
self.report({"WARNING"}, "No keyframes were found for this pose")
return {"CANCELLED"}
# Copy the asset metadata to the newly created asset.
asset.asset_data = context.id.asset_data
self._activate_asset_in_browser(context, asset)
# Delete the old asset
bpy.data.actions.remove(context.id)
# Now that the old name has become available, rename the asset to it.
asset.name = pose_name
return {'FINISHED'}
def _activate_asset_in_browser(self, context: Context, asset: Action) -> None:
"""Activate the new asset in the appropriate Asset Browser.
This makes it possible to immediately check & edit the created pose asset.
"""
asset_browse_area: Optional[bpy.types.Area] = asset_browser.area_from_context(context)
if not asset_browse_area:
return
# After creating an asset, the window manager has to process the
# notifiers before editors should be manipulated.
pose_creation.assign_from_asset_browser(asset, asset_browse_area)
# Pass deferred=True, because we just created a new asset that isn't
# known to the Asset Browser space yet. That requires the processing of
# notifiers, which will only happen after this code has finished
# running.
asset_browser.activate_asset(asset, asset_browse_area, deferred=True)
class POSELIB_OT_restore_previous_action(Operator):
bl_idname = "poselib.restore_previous_action"
bl_label = "Restore Previous Action"
@ -450,6 +515,7 @@ classes = (
POSELIB_OT_convert_old_object_poselib,
POSELIB_OT_copy_as_asset,
POSELIB_OT_create_pose_asset,
POSELIB_OT_replace_pose_asset,
POSELIB_OT_paste_asset,
POSELIB_OT_pose_asset_select_bones,
POSELIB_OT_restore_previous_action,