Anim: New/Un-assign Slot operators
All checks were successful
buildbot/vdev-code-daily-lint Build done.
buildbot/vdev-code-daily-darwin-x86_64 Build done.
buildbot/vdev-code-daily-darwin-arm64 Build done.
buildbot/vdev-code-daily-windows-amd64 Build done.
buildbot/vdev-code-daily-linux-x86_64 Build done.
buildbot/vdev-code-daily-coordinator Build done.
All checks were successful
buildbot/vdev-code-daily-lint Build done.
buildbot/vdev-code-daily-darwin-x86_64 Build done.
buildbot/vdev-code-daily-darwin-arm64 Build done.
buildbot/vdev-code-daily-windows-amd64 Build done.
buildbot/vdev-code-daily-linux-x86_64 Build done.
buildbot/vdev-code-daily-coordinator Build done.
Add two new operators, `anim.slot_new_for_id` and `anim.slot_unassign_from_id`. These are used in the Action editor and the Animation panels in the Properties editor, to respectively create a new Action Slot for an ID and to unassign whatever slot is currently assigned to that ID. The latter operator also replaces the C++ operator `anim.slot_unassign_object`, which was specifically made for the Dopesheet header. The Python ones are generic enough to be used there too. Pull Request: #126943
This commit is contained in:
parent
e143c0baee
commit
a6d7e12e22
@ -668,6 +668,69 @@ class ARMATURE_OT_collection_remove_unused(Operator):
|
||||
)
|
||||
|
||||
|
||||
class ANIM_OT_slot_new_for_id(Operator):
|
||||
"""Create a new Action Slot for an ID.
|
||||
|
||||
Note that _which_ ID should get this slot must be set in the 'animated_id' context pointer, using:
|
||||
|
||||
>>> layout.context_pointer_set("animated_id", animated_id)
|
||||
"""
|
||||
bl_idname = "anim.slot_new_for_id"
|
||||
bl_label = "New Slot"
|
||||
bl_description = "Create a new action slot for this data-block, to hold its animation"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
animated_id = getattr(context, 'animated_id', None)
|
||||
if not animated_id:
|
||||
return False
|
||||
if not animated_id.animation_data or not animated_id.animation_data.action:
|
||||
cls.poll_message_set("An action slot can only be created when an action was assigned")
|
||||
return False
|
||||
if not animated_id.animation_data.action.is_action_layered:
|
||||
cls.poll_message_set("Action slots are only supported by layered Actions. Upgrade this Action first")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
animated_id = getattr(context, 'animated_id', None)
|
||||
|
||||
action = animated_id.animation_data.action
|
||||
slot = action.slots.new(for_id=animated_id)
|
||||
animated_id.animation_data.action_slot = slot
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class ANIM_OT_slot_unassign_from_id(Operator):
|
||||
"""Un-assign the assigned Action Slot from an ID.
|
||||
|
||||
Note that _which_ ID should get this slot unassigned must be set in the
|
||||
'animated_id' context pointer, using:
|
||||
|
||||
>>> layout.context_pointer_set("animated_id", animated_id)
|
||||
"""
|
||||
bl_idname = "anim.slot_unassign_from_id"
|
||||
bl_label = "Unassign Slot"
|
||||
bl_description = "Un-assign the action slot, effectively making this data-block non-animated"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
animated_id = getattr(context, 'animated_id', None)
|
||||
if not animated_id:
|
||||
return False
|
||||
if not animated_id.animation_data or not animated_id.animation_data.action_slot:
|
||||
cls.poll_message_set("This data-block has no Action slot assigned")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
animated_id = getattr(context, 'animated_id', None)
|
||||
animated_id.animation_data.action_slot = None
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
classes = (
|
||||
ANIM_OT_keying_set_export,
|
||||
NLA_OT_bake,
|
||||
@ -677,4 +740,6 @@ classes = (
|
||||
ARMATURE_OT_collection_show_all,
|
||||
ARMATURE_OT_collection_unsolo_all,
|
||||
ARMATURE_OT_collection_remove_unused,
|
||||
ANIM_OT_slot_new_for_id,
|
||||
ANIM_OT_slot_unassign_from_id,
|
||||
)
|
||||
|
@ -225,8 +225,8 @@ class DOPESHEET_HT_header(Header):
|
||||
# Header for "normal" dopesheet editor modes (e.g. Dope Sheet, Action, Shape Keys, etc.)
|
||||
class DOPESHEET_HT_editor_buttons:
|
||||
|
||||
@staticmethod
|
||||
def draw_header(context, layout):
|
||||
@classmethod
|
||||
def draw_header(cls, context, layout):
|
||||
st = context.space_data
|
||||
tool_settings = context.tool_settings
|
||||
|
||||
@ -243,19 +243,7 @@ class DOPESHEET_HT_editor_buttons:
|
||||
|
||||
if context.object:
|
||||
layout.separator_spacer()
|
||||
layout.template_action(context.object, new="action.new", unlink="action.unlink")
|
||||
|
||||
# Show slot selector.
|
||||
if context.preferences.experimental.use_animation_baklava:
|
||||
# context.space_data.action comes from the active object.
|
||||
adt = context.object and context.object.animation_data
|
||||
if adt and st.action and st.action.is_action_layered:
|
||||
layout.template_search(
|
||||
adt, "action_slot",
|
||||
adt, "action_slots",
|
||||
new="anim.slot_new_for_object",
|
||||
unlink="anim.slot_unassign_object",
|
||||
)
|
||||
cls._draw_action_selector(context, layout)
|
||||
|
||||
# Layer management
|
||||
if st.mode == 'GPENCIL':
|
||||
@ -318,6 +306,27 @@ class DOPESHEET_HT_editor_buttons:
|
||||
panel="DOPESHEET_PT_proportional_edit",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _draw_action_selector(context, layout):
|
||||
layout.template_action(context.object, new="action.new", unlink="action.unlink")
|
||||
|
||||
if not context.preferences.experimental.use_animation_baklava:
|
||||
return
|
||||
|
||||
adt = context.object and context.object.animation_data
|
||||
if not adt or not adt.action or not adt.action.is_action_layered:
|
||||
return
|
||||
|
||||
# Store the animated ID in the context, so that the new/unlink operators
|
||||
# have access to it.
|
||||
layout.context_pointer_set("animated_id", context.object)
|
||||
layout.template_search(
|
||||
adt, "action_slot",
|
||||
adt, "action_slots",
|
||||
new="anim.slot_new_for_id",
|
||||
unlink="anim.slot_unassign_from_id",
|
||||
)
|
||||
|
||||
|
||||
class DOPESHEET_PT_snapping(Panel):
|
||||
bl_space_type = 'DOPESHEET_EDITOR'
|
||||
|
@ -125,11 +125,12 @@ class PropertiesAnimationMixin:
|
||||
|
||||
# Only show the slot selector when a layered Action is assigned.
|
||||
if adt.action.is_action_layered:
|
||||
layout.context_pointer_set("animated_id", animated_id)
|
||||
layout.template_search(
|
||||
adt, "action_slot",
|
||||
adt, "action_slots",
|
||||
new="", # TODO: add this operator.
|
||||
unlink="", # TODO: add this operator.
|
||||
new="anim.slot_new_for_id",
|
||||
unlink="anim.slot_unassign_from_id",
|
||||
)
|
||||
|
||||
|
||||
|
@ -715,7 +715,7 @@ static void ANIM_OT_scene_range_frame(wmOperatorType *ot)
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Slots
|
||||
/** \name Conversion
|
||||
* \{ */
|
||||
|
||||
static bool slot_new_for_object_poll(bContext *C)
|
||||
@ -770,49 +770,6 @@ static void ANIM_OT_slot_new_for_object(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static bool slot_unassign_object_poll(bContext *C)
|
||||
{
|
||||
Object *object = CTX_data_active_object(C);
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnimData *adt = BKE_animdata_from_id(&object->id);
|
||||
if (!adt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return adt->slot_handle != blender::animrig::Slot::unassigned;
|
||||
}
|
||||
|
||||
static int slot_unassign_object_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
Object *object = CTX_data_active_object(C);
|
||||
animrig::unassign_slot(object->id);
|
||||
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ANIM_OT_slot_unassign_object(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Unassign Slot";
|
||||
ot->idname = "ANIM_OT_slot_unassign_object";
|
||||
ot->description =
|
||||
"Clear the assigned action slot, effectively making this data-block non-animated";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = slot_unassign_object_exec;
|
||||
ot->poll = slot_unassign_object_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int convert_action_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
using namespace blender;
|
||||
@ -926,7 +883,6 @@ void ED_operatortypes_anim()
|
||||
WM_operatortype_append(ANIM_OT_keying_set_active_set);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_slot_new_for_object);
|
||||
WM_operatortype_append(ANIM_OT_slot_unassign_object);
|
||||
WM_operatortype_append(ANIM_OT_convert_legacy_action);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user