1 Commits

Author SHA1 Message Date
3dc5cff0a2 Move apply logic to common and eliminate selected bool 2024-12-27 02:28:38 -06:00
6 changed files with 464 additions and 378 deletions

View File

@ -1,63 +1,6 @@
# Yet Another Pose Library
# Damn Simple Pose Library
For Blender 3.5 - 4.3 (4.1 recommended).
In Blender 3.x, a new Asset-based Pose system was introduced.
That's fine and dandy, however because of that, the old Pose Library was deprecated and gutted out real quick-like. Too quick.
During the Blender 3.x releases, a new Asset-based Pose system was introduced. That's fine and dandy, but it was not (and still is not as of Jan 2025) ready to replace the old Action-based Pose Library system. The former Pose Library was quickly deprecated and removed, leaving legacy users high and dry.
This addon brings the Legacy Pose Library back as best as it can in a modern panel, and tries to stick as close to the old system as possible. Most, if not all existing Pose Libraries should work without any modifications. Little new is introduced outside of UI enhancements and handling for new data.
These excellent addons also address this removal in their own ways, check them out:
- [Sakura Poselib](https://github.com/kafuji/Sakura_Poselib)
- [gret](https://github.com/greisane/gret?tab=readme-ov-file#animation-actions-panel)
- [Amarillo's Pose Library](https://github.com/AmarilloArts/Amarillos-Pose-Library)
## Old Features
- The Pose Library list panel is ported from Armature Data Properties to a Sidebar (N) panel.
- Operators and data property [that were removed in 3.5](https://projects.blender.org/blender/blender/issues/93406) are ported from C to Python:
- `yapl.apply_pose`
- `yapl.browse_poses`
- `yapl.create_pose_library`
- `yapl.convert_pose_library`
- `yapl.add_pose`
- `yapl.move_pose`
- `yapl.remove_pose`
- `yapl.rename_pose`
- `yapl.unlink_pose_library`
- `Object.pose_library`
## New Features
- New panel interface for interacting with pose libraries, inspired by [gret's Actions Panel feature](https://github.com/greisane/gret?tab=readme-ov-file#animation-actions-panel).
- Hover over buttons for tooltips
- Operator to protect potentially-orphaned pose data (read Considerations)
- `yapl.protect_orphan_pose_library`
## Installation
1. [Download the repository as a zip](https://git.bkspl.me/breakingspell/YetAnotherPoseLibrary/archive/develop.zip), or otherwise clone the repository.
2. Install as an Add-on in Blender via Install -> Zip, and enable.
3. Optionally configure the suffix strings to fit your workflow, and whether the orhpan checker should run at startup.
## Usage
1. Open Sidebar (`N`), and choose the `Pose` tab.
2. Select an Armature Object, or an Object parented to an Armature.
3. Select existing Pose Library from drop-down, or create a new library.
### 3D View Hotkeys:
- `Shift + L` - Add/Replace Pose
- `Alt + L` - Browse Poses with Arrow Keys
### New Panel Controls
- `Single click` - Apply Pose
- `Shift + Click` - Rename Pose
- `Alt + Click` - Remove Pose
- `Ctrl + Click ` - Select Pose
- Choose `Edit` for fast Move/Rename/Removal
## Considerations
- Opening older scenes will cause existing Pose Libraries to unlink from their former targets and fall into orphan state. They can be re-linked and will retain their link when saved afterwards, but would otherwise disappear if saved without linking or protecting the datablock.
- This is due to the core DNA type `poselib` having been removed, so objects will drop the data. [There is no way to prevent this](https://developer.blender.org/docs/features/core/rna/#internals) as Python ID properties cannot be present at program runtime, only once the add-on is initialized.
- To mitgate, an operator is provided to protect orphaned pose libraries: `yapl.protect_orphan_pose_library`.
- This add-on was made much easier by the `pose_markers` property being retained for converting old pose libraries to the new asset system. If they decide to remove that property as well, there will be a need to improvise an index-based lookup.
This brings it back as best as it can.

View File

@ -1,12 +1,13 @@
import bpy
from . import gui, operators, common, keymaps
from . import gui, operators, common
from typing import List, Tuple
bl_info = \
{
"name": "Yet Another Pose Library",
"author": "breakingspell",
"version": (0, 1, 0),
"blender": (3, 6, 0),
"description": "Re-implement 3.x legacy Pose Library",
"name": "Damn Simple Pose Library",
"author": "jackie",
"version": (4, 1, 0),
"blender": (3, 5, 0),
"description": "woah",
"category": "Object Data",
}
@ -18,48 +19,87 @@ if _need_reload:
gui = importlib.reload(gui)
common = importlib.reload(common)
keymaps = importlib.reload(keymaps)
# keymaps = importlib.reload(keymaps)
operators = importlib.reload(operators)
# addon_keymaps: List[Tuple[bpy.types.KeyMap, bpy.types.KeyMapItem]] = []
# addon_keymaps = []
class yaplSettings(bpy.types.PropertyGroup):
class dsplObj(bpy.types.PropertyGroup):
pose_library: bpy.props.PointerProperty(
name="Active Pose Library", description="",
override={'LIBRARY_OVERRIDABLE'}, type=bpy.types.Action)
# update = common.poselib_update)
# , update = anim_layers.layer_name_update
class dsplVars(bpy.types.PropertyGroup):
pose_index: bpy.props.IntProperty(
name="Pose Index", description="", override={'LIBRARY_OVERRIDABLE'})
pose_new_name: bpy.props.StringProperty(
name="Pose Name", description="New name for pose",
default="Pose", override={'LIBRARY_OVERRIDABLE'})
numero: bpy.props.IntProperty(
name='Numero', default=666, override={'LIBRARY_OVERRIDABLE'})
class dsplSettings(bpy.types.PropertyGroup):
new_menu: bpy.props.BoolProperty(
name="New Menu", description="Toggle New Menu", default=True)
name="New Menu", description="Toggle New Menu", default=False)
edit_mode: bpy.props.BoolProperty(
name="Edit Mode", description="Toggle Edit Mode", default=False)
classes = yaplSettings
classes = (dsplObj, dsplVars, dsplSettings)
def pose_libraries_poll(self, action):
if getattr(action, "pose_markers", None):
return True
def register():
from bpy.utils import register_class
register_class(yaplSettings)
for cls in classes:
register_class(cls)
bpy.types.Object.pose_library = bpy.props.PointerProperty(
name="Active Pose Library", description="",
type=bpy.types.Action, override={'LIBRARY_OVERRIDABLE'},
poll=pose_libraries_poll)
# bpy.types.Armature.pose_library = bpy.props.PointerProperty(
# type=dsplObj, override={'LIBRARY_OVERRIDABLE'})
bpy.types.Scene.yaplSettings = bpy.props.PointerProperty(
type=yaplSettings, override={'LIBRARY_OVERRIDABLE'})
# bpy.types.Object.pose_library = bpy.props.PointerProperty(
# type=bpy.types.Action, options={'LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'})
bpy.types.Object.dspl = bpy.props.PointerProperty(
type=dsplObj, override={'LIBRARY_OVERRIDABLE'})
bpy.types.Object.dsplvars = bpy.props.PointerProperty(
type=dsplVars, override={'LIBRARY_OVERRIDABLE'})
bpy.types.Scene.dsplSettings = bpy.props.PointerProperty(
type=dsplSettings, override={'LIBRARY_OVERRIDABLE'})
gui.register()
operators.register()
keymaps.register()
def unregister():
# kc = bpy.context.window_manager.keyconfigs.addon
# km = kc.keymaps.new(name='3D View', space_type='VIEW_3D')
# kmi = [
# km.keymap_items.new("dspl.add_pose", type='L', value='PRESS', shift=True),
# km.keymap_items.new("dspl.browse_poses", type='L', value='PRESS', alt=True),
# ]
# addon_keymaps.append((km, kmi))
def unregister() -> None:
from bpy.utils import unregister_class
unregister_class(yaplSettings)
for cls in classes:
unregister_class(cls)
del bpy.types.Scene.yaplSettings
del bpy.types.Object.pose_library
del bpy.types.Object.dspl
del bpy.types.Object.dsplvars
del bpy.types.Scene.dsplSettings
keymaps.unregister()
operators.unregister()
gui.unregister()
operators.unregister()
# for km, kmi in addon_keymaps:
# km.keymap_items.remove(kmi)
# addon_keymaps.clear()
if __name__ == "__main__":
register()
register()

177
common.py
View File

@ -2,31 +2,51 @@ import bpy
import mathutils
def get_armature_data(context):
try:
arm_object = context.active_object
if arm_object and arm_object.type == "ARMATURE":
return arm_object, getattr(arm_object, "pose_library", None)
elif arm_object and arm_object.parent and arm_object.parent.type == "ARMATURE":
return arm_object.parent, getattr(arm_object.parent, "pose_library", None)
else:
return None, None
except:
return None, None
def getArmatureObject(context):
obj = context.active_object
if obj:
if obj.type == "ARMATURE":
return obj
elif obj.parent is not None and obj.parent.type == "ARMATURE":
return obj.parent
else:
return None
def get_armature_action(context):
def getLegacyPoseLibrary(context):
arm = getArmatureObject(context)
return getattr(arm, "pose_library", None)
def getArmatureAction(context):
arm = getArmatureObject(context)
return getattr(arm.animation_data, "action", None)
def getDsplAction(context):
arm = getArmatureObject(context)
return getattr(arm.dspl, "pose_library", None)
def getPoseLib(context):
arm = getArmatureObject(context)
pose_library_dspl = getDsplAction(context)
pose_library_action = getArmatureAction(context)
pose_library_legacy = getLegacyPoseLibrary(context)
if pose_library_dspl:
return pose_library_dspl
elif pose_library_action and not pose_library_dspl:
return pose_library_action
elif pose_library_legacy and not pose_library_dspl:
return pose_library_legacy
else:
return None
def searchPoseMarker(context, posename, type):
try:
arm_object, pose_library = get_armature_data(context)
if getattr(arm_object.animation_data.action, "pose_markers", None):
return getattr(arm_object.animation_data, "action", None)
except:
pass
def search_pose_marker(context, posename, type):
try:
arm_object, pose_library = get_armature_data(context)
pose_library = getPoseLib(context)
if type == "marker":
return pose_library.pose_markers.get(posename, None)
if type == "frame":
@ -37,12 +57,13 @@ def search_pose_marker(context, posename, type):
pass
def find_fcurve(context, bone_name, transform, index_int):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
def findFcurve(context, bone_name, transform, index_int):
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
active_frame = pose_markers.active.frame
fcurve_object = pose_library.fcurves.find(
fcurve_object = action_object.fcurves.find(
'pose.bones["'+bone_name+'"].'+transform+'', index=index_int)
if hasattr(fcurve_object, 'evaluate'):
return fcurve_object.evaluate(active_frame)
@ -50,31 +71,33 @@ def find_fcurve(context, bone_name, transform, index_int):
return None
def create_fcurve(context, bone_name, transform, index_int):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
def createFcurve(context, bone_name, transform, index_int):
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
try:
pose_library.fcurves.new(
action_object.fcurves.new(
'pose.bones["'+bone_name+'"].'+transform+'', index=index_int, action_group=bone_name)
return
except:
pass
def create_keyframe(context, bone_name, transform, index_int, new_marker, loc):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
def createKeyframe(context, bone_name, transform, index_int, new_marker, loc):
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
try:
pose_library.fcurves.find(
action_object.fcurves.find(
'pose.bones["'+bone_name+'"].'+transform+'', index=index_int).keyframe_points.insert(new_marker, loc)
return
except:
pass
def set_keyframes_from_bones(context, arm_object, new_marker):
def setKeyframesFromBones(context, arm_object, new_marker):
none_selected = True
for bone in arm_object.pose.bones:
if bone.bone.select:
@ -93,53 +116,53 @@ def set_keyframes_from_bones(context, arm_object, new_marker):
elif bone.rotation_mode == "QUATERNION":
rot_mode = "rotation_quaternion"
else:
self.report({'WARNING'}, "YAPL: Unsupported bone: " + bone.name + ": " + bone.rotation_mode)
print("Unsupported bone!")
rot_mode = None
loc_x = bone.location[0]
loc_y = bone.location[1]
loc_z = bone.location[2]
create_fcurve(context, bone_name, "location", 0)
create_fcurve(context, bone_name, "location", 1)
create_fcurve(context, bone_name, "location", 2)
create_keyframe(context, bone_name, "location", 0, new_marker, loc_x)
create_keyframe(context, bone_name, "location", 1, new_marker, loc_y)
create_keyframe(context, bone_name, "location", 2, new_marker, loc_z)
createFcurve(context, bone_name, "location", 0)
createFcurve(context, bone_name, "location", 1)
createFcurve(context, bone_name, "location", 2)
createKeyframe(context, bone_name, "location", 0, new_marker, loc_x)
createKeyframe(context, bone_name, "location", 1, new_marker, loc_y)
createKeyframe(context, bone_name, "location", 2, new_marker, loc_z)
if rot_mode == "rotation_quaternion":
rot_w = bone.rotation_quaternion[0]
rot_x = bone.rotation_quaternion[1]
rot_y = bone.rotation_quaternion[2]
rot_z = bone.rotation_quaternion[3]
create_fcurve(context, bone_name, rot_mode, 0)
create_fcurve(context, bone_name, rot_mode, 1)
create_fcurve(context, bone_name, rot_mode, 2)
create_fcurve(context, bone_name, rot_mode, 3)
create_keyframe(context, bone_name, rot_mode, 0, new_marker, rot_w)
create_keyframe(context, bone_name, rot_mode, 1, new_marker, rot_x)
create_keyframe(context, bone_name, rot_mode, 2, new_marker, rot_y)
create_keyframe(context, bone_name, rot_mode, 3, new_marker, rot_z)
createFcurve(context, bone_name, rot_mode, 0)
createFcurve(context, bone_name, rot_mode, 1)
createFcurve(context, bone_name, rot_mode, 2)
createFcurve(context, bone_name, rot_mode, 3)
createKeyframe(context, bone_name, rot_mode, 0, new_marker, rot_w)
createKeyframe(context, bone_name, rot_mode, 1, new_marker, rot_x)
createKeyframe(context, bone_name, rot_mode, 2, new_marker, rot_y)
createKeyframe(context, bone_name, rot_mode, 3, new_marker, rot_z)
elif rot_mode == "rotation_euler":
rot_x = bone.rotation_euler[0]
rot_y = bone.rotation_euler[1]
rot_z = bone.rotation_euler[2]
create_fcurve(context, bone_name, rot_mode, 0)
create_fcurve(context, bone_name, rot_mode, 1)
create_fcurve(context, bone_name, rot_mode, 2)
create_keyframe(context, bone_name, rot_mode, 0, new_marker, rot_x)
create_keyframe(context, bone_name, rot_mode, 1, new_marker, rot_y)
create_keyframe(context, bone_name, rot_mode, 2, new_marker, rot_z)
createFcurve(context, bone_name, rot_mode, 0)
createFcurve(context, bone_name, rot_mode, 1)
createFcurve(context, bone_name, rot_mode, 2)
createKeyframe(context, bone_name, rot_mode, 0, new_marker, rot_x)
createKeyframe(context, bone_name, rot_mode, 1, new_marker, rot_y)
createKeyframe(context, bone_name, rot_mode, 2, new_marker, rot_z)
scl_x = bone.scale[0]
scl_y = bone.scale[1]
scl_z = bone.scale[2]
create_fcurve(context, bone_name, "scale", 0)
create_fcurve(context, bone_name, "scale", 1)
create_fcurve(context, bone_name, "scale", 2)
create_keyframe(context, bone_name, "scale", 0, new_marker, scl_x)
create_keyframe(context, bone_name, "scale", 1, new_marker, scl_y)
create_keyframe(context, bone_name, "scale", 2, new_marker, scl_z)
createFcurve(context, bone_name, "scale", 0)
createFcurve(context, bone_name, "scale", 1)
createFcurve(context, bone_name, "scale", 2)
createKeyframe(context, bone_name, "scale", 0, new_marker, scl_x)
createKeyframe(context, bone_name, "scale", 1, new_marker, scl_y)
createKeyframe(context, bone_name, "scale", 2, new_marker, scl_z)
def set_bones_from_keyframes(context, arm_object, active_marker):
def setBonesfromKeyframes(context, arm_object, active_marker):
none_selected = True
for bone in arm_object.pose.bones:
if bone.bone.select:
@ -158,24 +181,24 @@ def set_bones_from_keyframes(context, arm_object, active_marker):
elif bone.rotation_mode == "QUATERNION":
rot_mode = "rotation_quaternion"
else:
self.report({'WARNING'}, "YAPL: Unsupported bone: " + bone.name + ": " + bone.rotation_mode)
print("Unsupported bone!")
rot_mode = None
loc_x = find_fcurve(context, bone_name, "location", 0) or 0.0
loc_y = find_fcurve(context, bone_name, "location", 1) or 0.0
loc_z = find_fcurve(context, bone_name, "location", 2) or 0.0
loc_x = findFcurve(context, bone_name, "location", 0) or 0.0
loc_y = findFcurve(context, bone_name, "location", 1) or 0.0
loc_z = findFcurve(context, bone_name, "location", 2) or 0.0
if rot_mode == "rotation_quaternion":
rot_w = find_fcurve(context, bone_name, rot_mode, 0) or 1.0
rot_x = find_fcurve(context, bone_name, rot_mode, 1) or 0.0
rot_y = find_fcurve(context, bone_name, rot_mode, 2) or 0.0
rot_z = find_fcurve(context, bone_name, rot_mode, 3) or 0.0
rot_w = findFcurve(context, bone_name, rot_mode, 0) or 1.0
rot_x = findFcurve(context, bone_name, rot_mode, 1) or 0.0
rot_y = findFcurve(context, bone_name, rot_mode, 2) or 0.0
rot_z = findFcurve(context, bone_name, rot_mode, 3) or 0.0
elif rot_mode == "rotation_euler":
rot_x = find_fcurve(context, bone_name, rot_mode, 0) or 0.0
rot_y = find_fcurve(context, bone_name, rot_mode, 1) or 0.0
rot_z = find_fcurve(context, bone_name, rot_mode, 2) or 0.0
scl_x = find_fcurve(context, bone_name, "scale", 0) or 1.0
scl_y = find_fcurve(context, bone_name, "scale", 1) or 1.0
scl_z = find_fcurve(context, bone_name, "scale", 2) or 1.0
rot_x = findFcurve(context, bone_name, rot_mode, 0) or 0.0
rot_y = findFcurve(context, bone_name, rot_mode, 1) or 0.0
rot_z = findFcurve(context, bone_name, rot_mode, 2) or 0.0
scl_x = findFcurve(context, bone_name, "scale", 0) or 1.0
scl_y = findFcurve(context, bone_name, "scale", 1) or 1.0
scl_z = findFcurve(context, bone_name, "scale", 2) or 1.0
bone.location = mathutils.Vector((loc_x, loc_y, loc_z))
if bone.rotation_mode == "XYZ":

147
gui.py
View File

@ -2,9 +2,9 @@ import bpy
from .common import *
class DATA_PT_YaplPanel(bpy.types.Panel):
bl_label = "Yet Another Pose Library"
bl_id = "DATA_PT_YaplPanel"
class DATA_PT_DSPLPanel(bpy.types.Panel):
bl_label = "Damn Simple Pose Library"
bl_id = "DATA_PT_DSPLPanel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Pose'
@ -14,14 +14,13 @@ class DATA_PT_YaplPanel(bpy.types.Panel):
return len(bpy.context.selected_objects)
def draw(self, context):
yapl_panel_layout = self.layout
yaplsettings = bpy.context.scene.yaplSettings
dspl_panel_layout = self.layout
dsplsettings = bpy.context.scene.dsplSettings
# Detect Armature object and parent
armature_layout = yapl_panel_layout.column(align=True)
armature_layout = dspl_panel_layout.column(align=True)
active_obj = context.active_object
arm_object, pose_library = get_armature_data(context)
pose_library_action = get_armature_action(context)
arm_object = getArmatureObject(context)
if arm_object:
if arm_object == active_obj:
@ -30,113 +29,119 @@ class DATA_PT_YaplPanel(bpy.types.Panel):
armature_layout.label(text=arm_object.name + " (Parent)")
# Attach or create pose library
if pose_library or pose_library_action:
if pose_library and not pose_library_action:
armature_layout.template_ID(
arm_object, "pose_library", new="yapl.create_pose_library", unlink="yapl.unlink_pose_library")
pose_library_dspl = getDsplAction(context)
pose_library_action = getArmatureAction(context)
elif pose_library_action and not pose_library:
if pose_library_dspl or pose_library_action:
if pose_library_dspl and not pose_library_action:
active_pose_library = pose_library_dspl
armature_layout.template_ID(
arm_object.animation_data, "action", new="yapl.create_pose_library")
armature_layout.label(
text="Pose Library detected as Action")
armature_layout.label(
text="You should convert to avoid problems")
armature_layout.operator(
"yapl.convert_pose_library", icon='PLUGIN', text="Convert to Pose Library")
arm_object.dspl, "pose_library", new="dspl.create_pose_library", unlink="dspl.unlink_pose_library")
elif pose_library and pose_library_action:
elif pose_library_action and not pose_library_dspl:
active_pose_library = pose_library_action
armature_layout.template_ID(
arm_object, "pose_library", new="yapl.create_pose_library")
armature_layout.label(text="Pose Library is opened as Action")
armature_layout.label(text="Keyframes will affect pose")
arm_object.animation_data, "action", new="dspl.create_pose_library")
armature_layout.label(
text="Legacy Pose Library detected.")
armature_layout.label(
text="You may convert to avoid problems")
armature_layout.operator(
"yapl.convert_pose_library", icon='PLUGIN', text="Unlink from Action")
"dspl.convert_pose_library", icon='PLUGIN', text="Convert to DSPL")
elif pose_library_action and pose_library_dspl:
armature_layout.template_ID(
arm_object.dspl, "pose_library", new="dspl.create_pose_library")
armature_layout.label(text="Double pose configuration!!")
armature_layout.label(text="You should not proceed")
armature_layout.operator(
"dspl.convert_pose_library", icon='PLUGIN', text="Convert to DSPL")
active_pose_library = pose_library_dspl
# List poses in pose library
if pose_library:
pose_box_layout = yapl_panel_layout.column()
if active_pose_library:
pose_box_layout = dspl_panel_layout.column()
# Menu switcher
pose_box_menu_switcher_layout = pose_box_layout.row()
pose_box_menu_switcher_layout.prop(
yaplsettings, "new_menu", icon='PMARKER_ACT', text="New Menu", toggle=True)
dsplsettings, "new_menu", icon='PMARKER_ACT', text="New Menu", toggle=True)
# Quick controls
quick_pose_controls_layout = pose_box_layout.column()
quick_pose_controls_layout.menu(
OBJECT_MT_AddPoseMenu.bl_idname, icon='ADD', text="New Pose")
if pose_library.pose_markers.active:
if active_pose_library.pose_markers.active:
quick_apply_layout = quick_pose_controls_layout.split(
align=True)
quick_apply_layout.operator(
"yapl.browse_poses", icon='CON_ARMATURE', text="Browse")
if yaplsettings.new_menu == False:
"dspl.browse_poses", icon='CON_ARMATURE', text="Browse")
if dsplsettings.new_menu == False:
quick_apply_layout.operator(
"yapl.apply_pose", icon='ARMATURE_DATA', text="Apply Pose").posename = pose_library.pose_markers.active.name
"dspl.apply_pose", icon='ARMATURE_DATA', text="Apply Pose").posename = active_pose_library.pose_markers.active.name
else:
quick_apply_layout.prop(yaplsettings,
quick_apply_layout.prop(dsplsettings,
"edit_mode", icon='GREASEPENCIL', text="Edit", toggle=True)
# New menu
if yaplsettings.new_menu == True:
if dsplsettings.new_menu == True:
pose_button_layout = pose_box_layout.row()
pose_button_entries_layout = pose_button_layout.column(align=True)
for pm in pose_library.pose_markers:
for pm in active_pose_library.pose_markers:
row = pose_button_entries_layout.row(align=True)
# Selected indicator
selected = pm.frame == pose_library.pose_markers.active.frame
if yaplsettings.edit_mode == False:
selected = pm.frame == active_pose_library.pose_markers.active.frame
if dsplsettings.edit_mode == False:
row.label(text="", icon='PMARKER_ACT' if selected else 'PMARKER_SEL')
# Pose operator buttons
if yaplsettings.edit_mode == True:
row.operator('yapl.rename_pose', text=pm.name).posename = pm.name
if dsplsettings.edit_mode == True:
row.operator('dspl.rename_pose', text=pm.name).posename = pm.name
else:
row.operator('yapl.apply_pose', text=pm.name).posename = pm.name
row.operator('dspl.apply_pose', text=pm.name).posename = pm.name
if yaplsettings.edit_mode == True:
movebuttondown = row.operator("yapl.move_pose", icon='TRIA_DOWN', text="")
if dsplsettings.edit_mode == True:
movebuttondown = row.operator("dspl.move_pose", icon='TRIA_DOWN', text="")
movebuttondown.direction = "DOWN"
movebuttondown.posename = pm.name
movebuttonup = row.operator("yapl.move_pose", icon='TRIA_UP', text="")
movebuttonup = row.operator("dspl.move_pose", icon='TRIA_UP', text="")
movebuttonup.direction = "UP"
movebuttonup.posename = pm.name
row.operator("yapl.remove_pose", icon='REMOVE', text="").posename = pm.name
row.operator("dspl.remove_pose", icon='REMOVE', text="").posename = pm.name
# Old menu
elif yaplsettings.new_menu == False:
elif dsplsettings.new_menu == False:
pose_list_layout = pose_box_layout.column()
# Pose list
pose_list_entries_layout = pose_list_layout.row()
pose_list_entries_layout.template_list("UI_UL_list","pose_markers",
pose_library, "pose_markers",
pose_library.pose_markers, "active_index", rows=4)
active_pose_library, "pose_markers",
active_pose_library.pose_markers, "active_index", rows=4)
# Pose operators
pose_ops_layout = pose_list_entries_layout.column(align=True)
pose_ops_layout.operator(
"wm.call_menu", icon='ADD', text="").name = "OBJECT_MT_AddPoseMenu"
if pose_library.pose_markers.active:
"dspl.draw_new_pose_menu", icon='ADD', text="")
if active_pose_library.pose_markers.active:
pose_ops_layout.operator(
"yapl.remove_pose", icon='REMOVE', text="")
"dspl.remove_pose", icon='REMOVE', text="")
pose_ops_layout.operator(
"yapl.apply_pose", icon='ARMATURE_DATA', text=""
).posename = pose_library.pose_markers.active.name
"dspl.apply_pose", icon='ARMATURE_DATA', text=""
).posename = active_pose_library.pose_markers.active.name
pose_ops_layout.operator(
"yapl.move_pose", icon='TRIA_UP', text="").direction = "UP"
"dspl.move_pose", icon='TRIA_UP', text="").direction = "UP"
pose_ops_layout.operator(
"yapl.move_pose", icon='TRIA_DOWN', text="").direction = "DOWN"
"dspl.move_pose", icon='TRIA_DOWN', text="").direction = "DOWN"
else:
armature_layout.label(
text="No Action or Pose Library detected")
armature_layout.template_ID(
arm_object, "pose_library", new="yapl.create_pose_library")
arm_object.dspl, "pose_library", new="dspl.create_pose_library")
else:
armature_layout.label(text="No armature or parent selected")
@ -147,34 +152,20 @@ class OBJECT_MT_AddPoseMenu(bpy.types.Menu):
bl_label = "Add Pose"
def draw(self, context):
arm_object, pose_library = get_armature_data(context)
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
yapl_add_menu_layout = self.layout
yapl_add_menu_layout.operator(
"yapl.add_pose", icon='ADD', text="Add New Pose")
if len(pose_library.pose_markers):
yapl_add_menu_layout.menu(
"OBJECT_MT_ReplacePoseMenu", text="Replace Existing Pose", icon="DECORATE_OVERRIDE")
class OBJECT_MT_ReplacePoseMenu(bpy.types.Menu):
bl_idname = "OBJECT_MT_ReplacePoseMenu"
bl_label = "Add Pose"
def draw(self, context):
arm_object, pose_library = get_armature_data(context)
yapl_replace_menu_layout = self.layout
for pm in pose_library.pose_markers:
op = yapl_replace_menu_layout.operator("yapl.add_pose", text=pm.name, icon="PMARKER")
op.replace = True
op.posename = pm.name
dspl_add_menu_layout = self.layout
dspl_add_menu_layout.operator(
"dspl.draw_new_pose_menu", icon='DECORATE_DRIVER', text="Add New Pose")
if action_object.pose_markers.active:
dspl_add_menu_layout.operator(
"dspl.add_pose", icon='DECORATE_OVERRIDE', text="Replace Existing Pose").replace = True
classes = (
DATA_PT_YaplPanel,
DATA_PT_DSPLPanel,
OBJECT_MT_AddPoseMenu,
OBJECT_MT_ReplacePoseMenu,
)

View File

@ -1,30 +1,28 @@
# SPDX-FileCopyrightText: 2010-2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from .operators import *
from typing import List, Tuple
addon_keymaps = []
def register_keymaps():
wm = bpy.context.window_manager
def register() -> None:
wm = bpy.context.window_manager
kc = wm.keyconfigs.addon
if kc is None:
return
km = kc.keymaps.new(name="File Browser Main")
kmi = km.keymap_items.new("dspl.browse_poses", type="L", value="PRESS", alt=True)
kmi.active = True
addon_keymaps.append((km, kmi))
# Add Pose
km = wm.keyconfigs.addon.keymaps.new(name='Pose', space_type='EMPTY')
kmi = km.keymap_items.new('wm.call_menu', 'L', 'PRESS', shift=True)
kmi.properties.name = "OBJECT_MT_AddPoseMenu"
addon_keymaps.append((km, kmi))
# Browse Poses
km = wm.keyconfigs.addon.keymaps.new(name='Pose', space_type='EMPTY')
kmi = km.keymap_items.new('yapl.browse_poses', 'L', 'PRESS', alt=True)
addon_keymaps.append((km, kmi))
def unregister_keymaps():
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()
def register():
register_keymaps()
def unregister():
unregister_keymaps()
def unregister() -> None:
for km, kmi in addon_keymaps:
km.keymap_items.remove(kmi)
addon_keymaps.clear()

View File

@ -6,55 +6,137 @@ from .common import *
# Operator to create a new pose library
class YAPL_OT_CreatePoseLibrary(bpy.types.Operator):
bl_idname = "yapl.create_pose_library"
class DSPL_OT_CreatePoseLibrary(bpy.types.Operator):
bl_idname = "dspl.create_pose_library"
bl_label = "Create Pose Library"
bl_description = "Create Pose Library"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
arm_object.pose_library = bpy.data.actions.new(
arm_object = getArmatureObject(context)
arm_object.dspl.pose_library = bpy.data.actions.new(
name=arm_object.name + "_PoseLib")
arm_object.pose_library.use_fake_user = True
arm_object.dspl.pose_library.use_fake_user = True
return {'FINISHED'}
# Operator to convert an action to pose library
# Operator to convert a pose library to dspl property
class YAPL_OT_ConvertPoseLibrary(bpy.types.Operator):
bl_idname = "yapl.convert_pose_library"
class DSPL_OT_ConvertPoseLibrary(bpy.types.Operator):
bl_idname = "dspl.convert_pose_library"
bl_label = "Convert Pose Library"
bl_description = "Convert Pose Library"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
if pose_library is None:
arm_object.pose_library = arm_object.animation_data.action
arm_object = getArmatureObject(context)
arm_object.dspl.pose_library = arm_object.animation_data.action
arm_object.animation_data.action = None
return {'FINISHED'}
# Operator to to draw a menu for new poses
class DSPL_OT_DrawNewPoseMenu(bpy.types.Operator):
bl_idname = "dspl.draw_new_pose_menu"
bl_label = "New Pose Menu"
bl_description = "New Pose Menu"
bl_options = {'INTERNAL'}
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
return context.window_manager.invoke_popup(self, width=200)
def draw(self, context):
dspl_create_popup_layout = self.layout
dspl_new_pose_menu = dspl_create_popup_layout.box()
arm_object = getArmatureObject(context)
pose_library = getPoseLib(context)
dspl_new_pose_menu.prop(
arm_object.dsplvars, "pose_new_name", text="Name")
# dspl_new_pose_menu.prop(
# # Might want to add this back in some form to match native copy/paste pose
# arm_object.dsplvars,
# "only_selected", icon='GROUP_BONE', text="Selected", toggle=True)
dspl_new_pose_menu.operator(
"dspl.add_pose", icon='ADD', text="Add New Pose").posename = arm_object.dsplvars.pose_new_name
# Operator to call up popup menus by ID
class DSPL_OT_CallPopupMenu(bpy.types.Operator):
bl_idname = "dspl.call_popup_menu"
bl_label = "Popup menu"
bl_description = "Popup menu"
bl_options = {'REGISTER', 'UNDO'}
menuID: bpy.props.StringProperty()
def execute(self, context):
bpy.ops.wm.call_menu(name=self.menuID)
return {'FINISHED'}
# Operator to manage the big menu buttons
class DSPL_OT_MenuButtonHandler(bpy.types.Operator):
bl_idname = "dspl.menu_button_handler"
bl_label = "Button Handler"
bl_description = "Button Handler"
bl_options = {'REGISTER', 'UNDO'}
posename: bpy.props.StringProperty()
def execute(self, context):
bpy.ops.wm.call_menu(name=self.menuID)
return {'FINISHED'}
def invoke(self, context, event):
if event.ctrl:
# Select
action_object = getPoseLib(context)
action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index")
return {'FINISHED'}
elif event.alt:
# Remove
bpy.ops.dspl.remove_pose(posename = self.posename)
return {'FINISHED'}
elif event.shift:
# Rename
bpy.ops.dspl.rename_pose(posename = self.posename)
return {'FINISHED'}
else:
return self.execute(context)
# Operator to add keyframes and marker to pose library
class YAPL_OT_AddPose(bpy.types.Operator):
bl_idname = "yapl.add_pose"
class DSPL_OT_AddPose(bpy.types.Operator):
bl_idname = "dspl.add_pose"
bl_label = "Add Pose"
bl_description = "Add Pose"
bl_options = {'REGISTER', 'UNDO'}
posename: bpy.props.StringProperty(default="Pose")
replace: bpy.props.BoolProperty(name="Replace", description="Replace existing pose", default=False, options={'SKIP_SAVE', 'HIDDEN'})
posename: bpy.props.StringProperty()
replace: bpy.props.BoolProperty(name="Replace", description="Replace existing pose", default=False, options={'SKIP_SAVE'})
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
if self.replace == False:
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
new_name = self.posename
counter = 1
@ -72,6 +154,7 @@ class YAPL_OT_AddPose(bpy.types.Operator):
# Check for duplicate names
while pose_markers.find(new_name) > -1:
print("Duplicate posename detected")
new_name = self.posename + ".{:03d}".format(counter)
counter += 1
else:
@ -80,17 +163,19 @@ class YAPL_OT_AddPose(bpy.types.Operator):
pose_markers.new(name=pose_name)
pose_markers[pose_name].frame = new_marker
set_keyframes_from_bones(context, arm_object, new_marker)
setKeyframesFromBones(context, arm_object, new_marker)
pose_library.pose_markers.active = pose_markers[pose_name]
action_object.pose_markers.active = pose_markers[pose_name]
bpy.context.area.tag_redraw()
self.report({'INFO'}, "YAPL: Added " + pose_markers[new_name].name + " to frame " + str(pose_markers[new_name].frame))
print("Added pose - " + pose_markers[new_name].name + " to frame " + str(pose_markers[new_name].frame))
else:
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
active_marker = pose_markers.active
new_name = self.posename
new_name = active_marker.name
counter = 1
for pm in pose_markers:
@ -105,9 +190,9 @@ class YAPL_OT_AddPose(bpy.types.Operator):
new_marker = target_frame
set_keyframes_from_bones(context, arm_object, new_marker)
setKeyframesFromBones(context, arm_object, new_marker)
self.report({'INFO'}, "YAPL: Replaced " + pose_markers[new_name].name + " on frame " + str(pose_markers[new_name].frame))
return {'FINISHED'}
@ -115,8 +200,8 @@ class YAPL_OT_AddPose(bpy.types.Operator):
# Operator to remove keyframes and marker
class YAPL_OT_RemovePose(bpy.types.Operator):
bl_idname = "yapl.remove_pose"
class DSPL_OT_RemovePose(bpy.types.Operator):
bl_idname = "dspl.remove_pose"
bl_label = "Remove Pose"
bl_description = "Remove Pose"
bl_options = {'REGISTER', 'UNDO'}
@ -124,17 +209,18 @@ class YAPL_OT_RemovePose(bpy.types.Operator):
posename: bpy.props.StringProperty()
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
if self.posename:
pose_library.pose_markers.active_index = search_pose_marker(context, posename=self.posename, type="index")
active_index = pose_library.pose_markers.active_index
action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index")
active_index = action_object.pose_markers.active_index
else:
active_index = pose_markers.active_index
active_marker = pose_markers.active
active_frame = active_marker.frame
fcurves = pose_library.fcurves
fcurves = action_object.fcurves
for fcu in fcurves:
for kf in fcu.keyframe_points.values():
if kf.co.x == active_frame:
@ -152,19 +238,18 @@ class YAPL_OT_RemovePose(bpy.types.Operator):
pose_markers.remove(marker=active_marker)
pose_library.pose_markers.active = next_marker
pose_library.pose_markers.active_index = next_index
self.report({'INFO'}, "YAPL: Removed " + self.posename)
print(next_index)
action_object.pose_markers.active = next_marker
action_object.pose_markers.active_index = next_index
return {'FINISHED'}
# Operator to rename the current pose
class YAPL_OT_RenamePose(bpy.types.Operator):
bl_idname = "yapl.rename_pose"
class DSPL_OT_RenamePose(bpy.types.Operator):
bl_idname = "dspl.rename_pose"
bl_label = "Rename Pose"
bl_description = "Rename Pose"
bl_options = {'REGISTER', 'UNDO'}
@ -173,21 +258,20 @@ class YAPL_OT_RenamePose(bpy.types.Operator):
pose_new_name: bpy.props.StringProperty()
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
active_marker = pose_markers.active
if self.posename:
target_marker = search_pose_marker(context, posename=self.posename, type="marker")
target_marker = searchPoseMarker(context, posename=self.posename, type="marker")
else:
target_marker = active_marker
if self.pose_new_name:
target_marker.name = self.pose_new_name
context.area.tag_redraw()
self.report({'INFO'}, "YAPL: Renamed " + self.posename + " to " + self.pose_new_name + " on frame " + str(active_marker.frame))
return {'FINISHED'}
else:
return {'FINISHED'}
@ -201,8 +285,8 @@ class YAPL_OT_RenamePose(bpy.types.Operator):
# Operator to reorder pose markers
class YAPL_OT_MovePose(bpy.types.Operator):
bl_idname = "yapl.move_pose"
class DSPL_OT_MovePose(bpy.types.Operator):
bl_idname = "dspl.move_pose"
bl_label = "Move Pose"
bl_description = "Move pose"
bl_options = {'REGISTER', 'UNDO'}
@ -211,15 +295,18 @@ class YAPL_OT_MovePose(bpy.types.Operator):
posename: bpy.props.StringProperty(name="Pose Name", default="", options={'SKIP_SAVE'})
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_lib = getPoseLib(context)
pose_markers = action_object.pose_markers
if self.posename:
active_index = search_pose_marker(context, posename=self.posename, type="index")
active_marker = search_pose_marker(context, posename=self.posename, type="marker")
active_index = searchPoseMarker(context, posename=self.posename, type="index")
active_marker = searchPoseMarker(context, posename=self.posename, type="marker")
active_frame = active_marker.frame
active_posename = active_marker.name
else:
arm_object = getArmatureObject(context)
active_marker = pose_markers.active
active_index = pose_markers.active_index
@ -231,19 +318,21 @@ class YAPL_OT_MovePose(bpy.types.Operator):
swap_index = active_index + move_dir
if swap_index < 0:
# swap_index = len(pose_lib.pose_markers) - 1
return {'FINISHED'}
elif swap_index >= len(pose_library.pose_markers):
elif swap_index >= len(pose_lib.pose_markers):
# swap_index = 0
return {'FINISHED'}
swap_marker = pose_markers[swap_index]
tmp_marker_name = swap_marker.name
tmp_marker_frame = swap_marker.frame
pose_library.pose_markers[swap_index].name = active_marker.name
pose_library.pose_markers[swap_index].frame = active_marker.frame
pose_library.pose_markers[active_index].name = tmp_marker_name
pose_library.pose_markers[active_index].frame = tmp_marker_frame
pose_library.pose_markers.active_index = swap_index
action_object.pose_markers[swap_index].name = active_marker.name
action_object.pose_markers[swap_index].frame = active_marker.frame
action_object.pose_markers[active_index].name = tmp_marker_name
action_object.pose_markers[active_index].frame = tmp_marker_frame
action_object.pose_markers.active_index = swap_index
return {'FINISHED'}
@ -251,49 +340,50 @@ class YAPL_OT_MovePose(bpy.types.Operator):
# Operator to apply a pose from active marker
class YAPL_OT_ApplyPose(bpy.types.Operator):
bl_idname = "yapl.apply_pose"
class DSPL_OT_ApplyPose(bpy.types.Operator):
bl_idname = "dspl.apply_pose"
bl_label = "Apply Pose"
bl_description = "Apply Pose (Ctrl+Click to select, Shift+Click to rename, Alt+Click to remove)"
bl_description = "Apply Pose (Ctrl+Click to select, Alt+Click to remove)"
bl_options = {'REGISTER', 'UNDO'}
posename: bpy.props.StringProperty()
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
pose_markers = pose_library.pose_markers
arm_object = getArmatureObject(context)
action_object = getPoseLib(context)
pose_markers = action_object.pose_markers
if self.posename:
active_marker = search_pose_marker(context, posename=self.posename, type="marker")
active_marker = searchPoseMarker(context, posename=self.posename, type="marker")
active_frame = active_marker.frame
active_posename = active_marker.name
pose_library.pose_markers.active_index = search_pose_marker(context, posename=self.posename, type="index")
action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index")
else:
active_index = pose_markers.active_index
active_marker = pose_markers.active
active_frame = active_marker.frame
active_posename = active_marker.name
set_bones_from_keyframes(context, arm_object, active_marker)
setBonesfromKeyframes(context, arm_object, active_marker)
self.report({'INFO'}, "YAPL: Applied " + active_posename)
print("Applied pose - " + active_posename)
return {'FINISHED'}
def invoke(self, context, event):
if event.ctrl:
# Select
arm_object, pose_library = get_armature_data(context)
pose_library.pose_markers.active_index = search_pose_marker(context, posename=self.posename, type="index")
action_object = getPoseLib(context)
action_object.pose_markers.active_index = searchPoseMarker(context, posename=self.posename, type="index")
return {'FINISHED'}
elif event.alt:
# Remove
bpy.ops.yapl.remove_pose(posename = self.posename)
bpy.ops.dspl.remove_pose(posename = self.posename)
return {'FINISHED'}
elif event.shift:
# Rename
bpy.ops.yapl.rename_pose('INVOKE_DEFAULT', posename = self.posename)
bpy.ops.dspl.rename_pose(posename = self.posename)
return {'FINISHED'}
else:
return self.execute(context)
@ -302,8 +392,8 @@ class YAPL_OT_ApplyPose(bpy.types.Operator):
# Operator to preview up and down pose list
class YAPL_OT_BrowsePoses(bpy.types.Operator):
bl_idname = "yapl.browse_poses"
class DSPL_OT_BrowsePoses(bpy.types.Operator):
bl_idname = "dspl.browse_poses"
bl_label = "Browse Poses"
bl_description = "Browse Poses"
bl_options = {'REGISTER', 'UNDO'}
@ -315,7 +405,7 @@ class YAPL_OT_BrowsePoses(bpy.types.Operator):
font_dpi = 72
blf.position(font_id, 15, 30, 0)
mod_var = self.pose_library.pose_markers.active.name
mod_var = self.pose_lib.pose_markers.active.name
blf.color(font_id, 1.0, 1.0, 1.0, 1.0)
blf.size(font_id, font_size)
blf.draw(font_id, "Previewing pose: " + mod_var)
@ -326,17 +416,17 @@ class YAPL_OT_BrowsePoses(bpy.types.Operator):
if event.value == 'PRESS':
if event.type in {'LEFT_ARROW', 'UP_ARROW'}:
if self.pose_library.pose_markers.active_index <= 0:
self.pose_library.pose_markers.active_index = len(self.pose_library.pose_markers) - 1
if self.pose_lib.pose_markers.active_index <= 0:
self.pose_lib.pose_markers.active_index = len(self.pose_lib.pose_markers) - 1
else:
self.pose_library.pose_markers.active_index = self.pose_library.pose_markers.active_index - 1
bpy.ops.yapl.apply_pose()
self.pose_lib.pose_markers.active_index = self.pose_lib.pose_markers.active_index - 1
bpy.ops.dspl.apply_pose()
elif event.type in {'RIGHT_ARROW', 'DOWN_ARROW'}:
if self.pose_library.pose_markers.active_index + 1 >= len(self.pose_library.pose_markers):
self.pose_library.pose_markers.active_index = 0
if self.pose_lib.pose_markers.active_index + 1 >= len(self.pose_lib.pose_markers):
self.pose_lib.pose_markers.active_index = 0
else:
self.pose_library.pose_markers.active_index = self.pose_library.pose_markers.active_index + 1
bpy.ops.yapl.apply_pose()
self.pose_lib.pose_markers.active_index = self.pose_lib.pose_markers.active_index + 1
bpy.ops.dspl.apply_pose()
if event.type in {'LEFTMOUSE', 'RET', 'NUMPAD_ENTER'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
@ -344,7 +434,7 @@ class YAPL_OT_BrowsePoses(bpy.types.Operator):
elif event.type in {'RIGHTMOUSE', 'ESC'}:
self.arm_object.pose.backup_restore()
self.pose_library.pose_markers.active_index = self.backup_index
self.pose_lib.pose_markers.active_index = self.backup_index
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'CANCELLED'}
@ -354,44 +444,42 @@ class YAPL_OT_BrowsePoses(bpy.types.Operator):
def invoke(self, context, event):
bpy.context.area.tag_redraw()
self.arm_object, self.pose_library = get_armature_data(context)
if self.pose_library is None:
self.report({'WARNING'}, "YAPL: Pose Library not active")
self.arm_object = getArmatureObject(context)
self.pose_lib = getPoseLib(context)
if self.pose_lib is None:
self.report({'WARNING'}, "Pose Library not active")
return {'CANCELLED'}
self.arm_object.pose.backup_create(self.pose_library)
self.backup_index = self.pose_library.pose_markers.active_index
bpy.ops.yapl.apply_pose()
self.arm_object.pose.backup_create(self.pose_lib)
self.backup_index = self.pose_lib.pose_markers.active_index
bpy.ops.dspl.apply_pose()
if context.area.type == 'VIEW_3D':
self.report({'INFO'}, "YAPL: Browsing Poses")
print("Starting modal")
args = (self, context)
self._handle = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
print("not in 3d")
return {'CANCELLED'}
# Operator to unlink a pose library and mark for removal
class YAPL_OT_UnlinkPoseLibrary(bpy.types.Operator):
bl_idname = "yapl.unlink_pose_library"
class DSPL_OT_UnlinkPoseLibrary(bpy.types.Operator):
bl_idname = "dspl.unlink_pose_library"
bl_label = "Unlink Pose Library"
bl_description = "Unlink Pose Library"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
arm_object, pose_library = get_armature_data(context)
arm_object = getArmatureObject(context)
pose_library = getPoseLib(context)
try:
arm_object.pose_library = None
# arm_object.pose_library.use_fake_user = False
# if not arm_object.pose_library.name.startswith("del_"):
# arm_object.pose_library.name = "del_{}".format(arm_object.pose_library.name)
except:
pass
arm_object.dspl.pose_library.name = "del_" + arm_object.dspl.pose_library.name
arm_object.dspl.pose_library = None
return {'FINISHED'}
@ -399,8 +487,8 @@ class YAPL_OT_UnlinkPoseLibrary(bpy.types.Operator):
# Operator to protect orphaned legacy pose libraries
class YAPL_OT_ProtectOrphanPoseLibrary(bpy.types.Operator):
bl_idname = "yapl.protect_orphan_pose_library"
class DSPL_OT_ProtectOrphanPoseLibrary(bpy.types.Operator):
bl_idname = "dspl.protect_orphan_pose_library"
bl_label = "Protect Orphaned Pose Libraries"
bl_description = "Protect Orphaned Pose Libraries"
bl_options = {'REGISTER', 'UNDO'}
@ -436,23 +524,26 @@ class YAPL_OT_ProtectOrphanPoseLibrary(bpy.types.Operator):
if orphaned_act:
for act in orphaned_act:
if "_loc" in act.name or "PoseLib" in act.name:
self.report({'INFO'}, "YAPL: Protecting orphaned action: " + act.name)
print("Protecting orphaned action: " + act.name)
act.use_fake_user = True
return {'FINISHED'}
classes = (
YAPL_OT_CreatePoseLibrary,
YAPL_OT_ConvertPoseLibrary,
YAPL_OT_AddPose,
YAPL_OT_RemovePose,
YAPL_OT_RenamePose,
YAPL_OT_MovePose,
YAPL_OT_ApplyPose,
YAPL_OT_BrowsePoses,
YAPL_OT_UnlinkPoseLibrary,
YAPL_OT_ProtectOrphanPoseLibrary
DSPL_OT_CreatePoseLibrary,
DSPL_OT_ConvertPoseLibrary,
DSPL_OT_CallPopupMenu,
DSPL_OT_DrawNewPoseMenu,
DSPL_OT_MenuButtonHandler,
DSPL_OT_AddPose,
DSPL_OT_RemovePose,
DSPL_OT_RenamePose,
DSPL_OT_MovePose,
DSPL_OT_ApplyPose,
DSPL_OT_BrowsePoses,
DSPL_OT_UnlinkPoseLibrary,
DSPL_OT_ProtectOrphanPoseLibrary
)
register, unregister = bpy.utils.register_classes_factory(classes)