Anim: Separate Slots operator
This adds an operator that splits all slots of the action on the active object, into separate actions. The newly created actions will be named `slot_name+Action`. All users of those slots will be reassigned to this new action. The exploded action will not be deleted, but will end up with 0 users unless a fake user is set. ------ For the review, does that operator name make sense? Pull Request: https://projects.blender.org/blender/blender/pulls/128251
This commit is contained in:
committed by
Christoph Lendenfeld
parent
ad2207243a
commit
85e4bd19f6
@@ -590,8 +590,11 @@ class DOPESHEET_MT_action(Menu):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("anim.slot_channels_move_to_new_action")
|
||||
layout.operator("anim.merge_animation")
|
||||
layout.operator("anim.separate_slots")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("anim.slot_channels_move_to_new_action")
|
||||
|
||||
|
||||
class DOPESHEET_MT_key(Menu):
|
||||
|
||||
@@ -5284,6 +5284,70 @@ static void ANIM_OT_slot_channels_move_to_new_action(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int separate_slots_exec(bContext *C, wmOperator * /* op */)
|
||||
{
|
||||
using namespace blender::animrig;
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
/* Checked by the poll function. */
|
||||
BLI_assert(active_object != nullptr);
|
||||
|
||||
Action *action = get_action(active_object->id);
|
||||
/* Also checked by the poll function. */
|
||||
BLI_assert(action != nullptr);
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
while (action->slot_array_num) {
|
||||
Slot *slot = action->slot(action->slot_array_num - 1);
|
||||
char actname[MAX_ID_NAME - 2];
|
||||
SNPRINTF(actname, DATA_("%sAction"), slot->name + 2);
|
||||
Action &target_action = action_add(*bmain, actname);
|
||||
Layer &layer = target_action.layer_add(std::nullopt);
|
||||
layer.strip_add(target_action, Strip::Type::Keyframe);
|
||||
move_slot(*bmain, *slot, *action, target_action);
|
||||
DEG_id_tag_update(&target_action.id, ID_RECALC_ANIMATION_NO_FLUSH);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&action->id, ID_RECALC_ANIMATION_NO_FLUSH);
|
||||
DEG_relations_tag_update(CTX_data_main(C));
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE | NA_EDITED, nullptr);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static bool separate_slots_poll(bContext *C)
|
||||
{
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
if (!active_object) {
|
||||
CTX_wm_operator_poll_msg_set(C, "No active object");
|
||||
return false;
|
||||
}
|
||||
|
||||
blender::animrig::Action *action = blender::animrig::get_action(active_object->id);
|
||||
if (!action) {
|
||||
CTX_wm_operator_poll_msg_set(C, "Active object isn't animated");
|
||||
return false;
|
||||
}
|
||||
if (!action->is_action_layered()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ANIM_OT_separate_slots(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Separate Slots";
|
||||
ot->idname = "ANIM_OT_separate_slots";
|
||||
ot->description =
|
||||
"Move all slots of the action on the active object into newly created, separate actions. "
|
||||
"All users of those slots will be reassigned to the new actions. The current action won't "
|
||||
"be deleted but will be empty and might end up having zero users";
|
||||
|
||||
ot->exec = separate_slots_exec;
|
||||
ot->poll = separate_slots_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
#endif /* WITH_ANIM_BAKLAVA */
|
||||
|
||||
/**
|
||||
@@ -5670,6 +5734,7 @@ void ED_operatortypes_animchannels()
|
||||
|
||||
#ifdef WITH_ANIM_BAKLAVA
|
||||
WM_operatortype_append(ANIM_OT_slot_channels_move_to_new_action);
|
||||
WM_operatortype_append(ANIM_OT_separate_slots);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user