diff --git a/scripts/startup/bl_ui/space_sequencer.py b/scripts/startup/bl_ui/space_sequencer.py index 52b629db9bd..d8677ed64e1 100644 --- a/scripts/startup/bl_ui/space_sequencer.py +++ b/scripts/startup/bl_ui/space_sequencer.py @@ -991,6 +991,7 @@ class SEQUENCER_MT_strip_animation(Menu): layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True layout.operator("anim.keying_set_active_set", text="Change Keying Set...") layout.operator("anim.keyframe_delete_vse", text="Delete Keyframes...") + layout.operator("anim.keyframe_clear_vse", text="Clear Keyframes...") class SEQUENCER_MT_strip_input(Menu): diff --git a/source/blender/editors/animation/anim_intern.hh b/source/blender/editors/animation/anim_intern.hh index 043df9e71e3..f7b9225a761 100644 --- a/source/blender/editors/animation/anim_intern.hh +++ b/source/blender/editors/animation/anim_intern.hh @@ -47,6 +47,7 @@ void ANIM_OT_keyframe_insert_menu(wmOperatorType *ot); void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot); void ANIM_OT_keyframe_delete_vse(wmOperatorType *ot); void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot); +void ANIM_OT_keyframe_clear_vse(wmOperatorType *ot); /** \} */ diff --git a/source/blender/editors/animation/anim_ops.cc b/source/blender/editors/animation/anim_ops.cc index 4dc3000f7aa..45b420ac2cd 100644 --- a/source/blender/editors/animation/anim_ops.cc +++ b/source/blender/editors/animation/anim_ops.cc @@ -1376,6 +1376,7 @@ void ED_operatortypes_anim() WM_operatortype_append(ANIM_OT_keyframe_delete_v3d); WM_operatortype_append(ANIM_OT_keyframe_delete_vse); WM_operatortype_append(ANIM_OT_keyframe_clear_v3d); + WM_operatortype_append(ANIM_OT_keyframe_clear_vse); WM_operatortype_append(ANIM_OT_keyframe_insert_button); WM_operatortype_append(ANIM_OT_keyframe_delete_button); WM_operatortype_append(ANIM_OT_keyframe_clear_button); diff --git a/source/blender/editors/animation/keyframing.cc b/source/blender/editors/animation/keyframing.cc index 95f936edb59..c6e3c1195c5 100644 --- a/source/blender/editors/animation/keyframing.cc +++ b/source/blender/editors/animation/keyframing.cc @@ -849,6 +849,94 @@ static bool fcurve_belongs_to_strip(const FCurve &fcurve, const std::string &str return fcurve.rna_path && std::strncmp(fcurve.rna_path, strip_path.c_str(), strip_path.length()) == 0; } + +static wmOperatorStatus clear_anim_vse_exec(bContext *C, wmOperator *op) +{ + using namespace blender::animrig; + bool changed = false; + + Scene *scene = CTX_data_scene(C); + + blender::Vector selection; + blender::Vector selected_strips_rna_paths; + get_selection(C, &selection); + selected_strips_rna_paths = get_selected_strips_rna_paths(selection); + + if (selected_strips_rna_paths.is_empty()) { + BKE_reportf(op->reports, RPT_WARNING, "No strips selected"); + return OPERATOR_CANCELLED; + } + + if (!scene->adt || !scene->adt->action || (scene->adt->slot_handle == Slot::unassigned)) { + BKE_reportf(op->reports, RPT_ERROR, "Scene has no animation data or active action"); + return OPERATOR_CANCELLED; + } + + AnimData *adt = scene->adt; + bAction *dna_action = adt->action; + + Action &action = dna_action->wrap(); + blender::Vector fcurves_to_delete; + foreach_fcurve_in_action_slot(action, adt->slot_handle, [&](FCurve &fcurve) { + for (const std::string &strip_path : selected_strips_rna_paths) { + if (fcurve_belongs_to_strip(fcurve, strip_path)) { + fcurves_to_delete.append(&fcurve); + break; + } + } + }); + for (FCurve *fcurve : fcurves_to_delete) { + action_fcurve_remove(action, *fcurve); + changed = true; + } + + if (!changed) { + return OPERATOR_CANCELLED; + } + + if (scene->adt->action) { + DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); + } + invalidate_strip_caches(selection, scene); + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + WM_event_add_notifier(C, NC_ANIMATION, nullptr); + + return OPERATOR_FINISHED; +} + +static wmOperatorStatus clear_anim_vse_invoke(bContext *C, + wmOperator *op, + const wmEvent * /*event*/) +{ + if (RNA_boolean_get(op->ptr, "confirm")) { + return WM_operator_confirm_ex(C, + op, + IFACE_("Remove animation from selected strips?"), + nullptr, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove"), + ALERT_ICON_NONE, + false); + } + return clear_anim_vse_exec(C, op); +} +void ANIM_OT_keyframe_clear_vse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Animation"; + ot->description = "Remove all keyframe animation for selected strips"; + ot->idname = "ANIM_OT_keyframe_clear_vse"; + + /* callbacks */ + ot->invoke = clear_anim_vse_invoke; + ot->exec = clear_anim_vse_exec; + + ot->poll = ED_operator_areaactive; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + WM_operator_properties_confirm_or_exec(ot); +} + static bool can_delete_key(FCurve *fcu, Object *ob, ReportList *reports) { /* don't touch protected F-Curves */