diff --git a/source/blender/blenkernel/BKE_nla.hh b/source/blender/blenkernel/BKE_nla.hh index cc064fe6734..15f3e751a40 100644 --- a/source/blender/blenkernel/BKE_nla.hh +++ b/source/blender/blenkernel/BKE_nla.hh @@ -460,6 +460,15 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks); */ void BKE_nlastrip_validate_fcurves(NlaStrip *strip); +/** + * Delete the NLA-Strip's control F-Curve. + * + * This also ensures that the strip's flags are correctly updated. + * + * \return Whether the F-Curve was actually removed. + */ +bool BKE_nlastrip_controlcurve_remove(NlaStrip *strip, FCurve *fcurve); + /** * Check if the given RNA pointer + property combo should be handled by * NLA strip curves or not. diff --git a/source/blender/blenkernel/intern/nla.cc b/source/blender/blenkernel/intern/nla.cc index 4cde6c46356..f9d2f87caa0 100644 --- a/source/blender/blenkernel/intern/nla.cc +++ b/source/blender/blenkernel/intern/nla.cc @@ -1862,6 +1862,23 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip) } } +bool BKE_nlastrip_controlcurve_remove(NlaStrip *strip, FCurve *fcurve) +{ + if (STREQ(fcurve->rna_path, "strip_time")) { + strip->flag &= ~NLASTRIP_FLAG_USR_TIME; + } + else if (STREQ(fcurve->rna_path, "influence")) { + strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE; + } + else { + return false; + } + + BLI_remlink(&strip->fcurves, fcurve); + BKE_fcurve_free(fcurve); + return true; +} + bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop) { /* sanity checks */ diff --git a/source/blender/editors/animation/anim_channels_edit.cc b/source/blender/editors/animation/anim_channels_edit.cc index e4ab90b827e..c18e45968a5 100644 --- a/source/blender/editors/animation/anim_channels_edit.cc +++ b/source/blender/editors/animation/anim_channels_edit.cc @@ -2905,6 +2905,54 @@ static bool animchannels_delete_containers(const bContext *C, bAnimContext *ac) return has_skipped_group; } +void ED_anim_ale_fcurve_delete(bAnimContext &ac, bAnimListElem &ale) +{ + BLI_assert(ELEM(ale.type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)); + + switch (ale.type) { + case ANIMTYPE_FCURVE: { + AnimData *adt = ale.adt; + FCurve *fcu = static_cast(ale.data); + + BLI_assert_msg((fcu->driver != nullptr) == (ac.datatype == ANIMCONT_DRIVERS), + "Expecting only driver F-Curves in the drivers editor"); + + if (ale.fcurve_owner_id && GS(ale.fcurve_owner_id->name) == ID_AC) { + /* F-Curves can be owned by Actions assigned to NLA strips, which + * `animrig::animdata_fcurve_delete()` (below) cannot handle. */ + BLI_assert_msg(!fcu->driver, "Drivers are not expected to be owned by Actions"); + blender::animrig::Action &action = + reinterpret_cast(ale.fcurve_owner_id)->wrap(); + BLI_assert(!action.is_action_legacy()); + action_fcurve_remove(action, *fcu); + } + else if (fcu->driver || adt->action) { + /* This function only works for drivers & directly-assigned Actions: */ + blender::animrig::animdata_fcurve_delete(adt, fcu); + } + else { + BLI_assert_unreachable(); + } + break; + } + case ANIMTYPE_NLACURVE: { + /* NLA Control Curve. */ + NlaStrip *strip = static_cast(ale.owner); + FCurve *fcu = static_cast(ale.data); + if (!BKE_nlastrip_controlcurve_remove(strip, fcu)) { + printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", + fcu->rna_path); + } + break; + } + + default: + BLI_assert_unreachable(); + } + + tag_update_animation_element(&ale); +} + static wmOperatorStatus animchannels_delete_exec(bContext *C, wmOperator * /*op*/) { bAnimContext ac; @@ -2941,55 +2989,11 @@ static wmOperatorStatus animchannels_delete_exec(bContext *C, wmOperator * /*op* /* delete selected data channels */ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { switch (ale->type) { - case ANIMTYPE_FCURVE: { - /* F-Curves if we can identify its parent */ - AnimData *adt = ale->adt; - FCurve *fcu = static_cast(ale->data); - - /* try to free F-Curve */ - BLI_assert_msg((fcu->driver != nullptr) == (ac.datatype == ANIMCONT_DRIVERS), - "Expecting only driver F-Curves in the drivers editor"); - if (ale->fcurve_owner_id && GS(ale->fcurve_owner_id->name) == ID_AC) { - /* F-Curves can be owned by Actions assigned to NLA strips, which - * `animrig::animdata_fcurve_delete()` (below) cannot handle. */ - BLI_assert_msg(!fcu->driver, "Drivers are not expected to be owned by Actions"); - blender::animrig::Action &action = - reinterpret_cast(ale->fcurve_owner_id)->wrap(); - BLI_assert(!action.is_action_legacy()); - action_fcurve_remove(action, *fcu); - } - else if (fcu->driver || adt->action) { - /* This function only works for drivers & directly-assigned Actions: */ - blender::animrig::animdata_fcurve_delete(adt, fcu); - } - else { - BLI_assert_unreachable(); - } - tag_update_animation_element(ale); + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: + ED_anim_ale_fcurve_delete(ac, *ale); break; - } - case ANIMTYPE_NLACURVE: { - /* NLA Control Curve - Deleting it should disable the corresponding setting... */ - NlaStrip *strip = static_cast(ale->owner); - FCurve *fcu = static_cast(ale->data); - if (STREQ(fcu->rna_path, "strip_time")) { - strip->flag &= ~NLASTRIP_FLAG_USR_TIME; - } - else if (STREQ(fcu->rna_path, "influence")) { - strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE; - } - else { - printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", - fcu->rna_path); - } - - /* unlink and free the F-Curve */ - BLI_remlink(&strip->fcurves, fcu); - BKE_fcurve_free(fcu); - tag_update_animation_element(ale); - break; - } case ANIMTYPE_GPLAYER: { /* Grease Pencil layer */ bGPdata *gpd = reinterpret_cast(ale->id); diff --git a/source/blender/editors/include/ED_anim_api.hh b/source/blender/editors/include/ED_anim_api.hh index 0bfb106f405..334101c7519 100644 --- a/source/blender/editors/include/ED_anim_api.hh +++ b/source/blender/editors/include/ED_anim_api.hh @@ -1231,6 +1231,14 @@ void ED_animedit_unlink_action( */ void ED_drivers_editor_init(bContext *C, ScrArea *area); +/** + * Delete an F-Curve from its owner. + * + * This can delete an F-Curve from an Action (both directly assigned and via an + * NLA strip), Drivers, and NLA control curves. + */ +void ED_anim_ale_fcurve_delete(bAnimContext &ac, bAnimListElem &ale); + /* ************************************************ */ enum eAnimvizCalcRange { diff --git a/source/blender/editors/space_action/action_edit.cc b/source/blender/editors/space_action/action_edit.cc index 2fa5dfe0cfc..1f48e4a615c 100644 --- a/source/blender/editors/space_action/action_edit.cc +++ b/source/blender/editors/space_action/action_edit.cc @@ -1144,15 +1144,11 @@ static bool delete_action_keys(bAnimContext *ac) changed = ED_masklayer_frames_delete((MaskLayer *)ale->data); } else { - FCurve *fcu = (FCurve *)ale->key_data; - AnimData *adt = ale->adt; - - /* delete selected keyframes only */ + FCurve *fcu = static_cast(ale->key_data); changed = BKE_fcurve_delete_keys_selected(fcu); - /* Only delete curve too if it won't be doing anything anymore */ - if (BKE_fcurve_is_empty(fcu)) { - blender::animrig::animdata_fcurve_delete(adt, fcu); + if (changed && BKE_fcurve_is_empty(fcu)) { + ED_anim_ale_fcurve_delete(*ac, *ale); ale->key_data = nullptr; } }