diff options
-rw-r--r-- | source/blender/editors/animation/anim_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/anim_ops.c | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 157 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_anim.c | 6 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 28 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 1 |
6 files changed, 190 insertions, 4 deletions
diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index 7d1209a3033..cf84eb04b10 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -55,6 +55,7 @@ void ANIM_OT_keyframe_delete_v3d(struct wmOperatorType *ot); /* Keyframe managment operators for UI buttons (RMB menu). */ void ANIM_OT_keyframe_insert_button(struct wmOperatorType *ot); void ANIM_OT_keyframe_delete_button(struct wmOperatorType *ot); +void ANIM_OT_keyframe_clear_button(struct wmOperatorType *ot); /* .......... */ diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 119df33dd91..13741a99d99 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -294,6 +294,7 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_keyframe_delete_v3d); WM_operatortype_append(ANIM_OT_keyframe_insert_button); WM_operatortype_append(ANIM_OT_keyframe_delete_button); + WM_operatortype_append(ANIM_OT_keyframe_clear_button); WM_operatortype_append(ANIM_OT_driver_button_add); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 7600e1d4690..3ef686910e6 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1079,6 +1079,91 @@ short delete_keyframe(ReportList *reports, ID *id, bAction *act, const char grou return ret; } +/* ************************************************** */ +/* KEYFRAME CLEAR */ + +/* Main Keyframing API call: + * Use this when validation of necessary animation data isn't necessary as it + * already exists. It will clear the current buttons fcurve(s). + * + * The flag argument is used for special settings that alter the behavior of + * the keyframe deletion. These include the quick refresh options. + */ +short clear_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, short UNUSED(flag)) +{ + AnimData *adt = BKE_animdata_from_id(id); + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + int array_index_max = array_index + 1; + int ret = 0; + + /* sanity checks */ + if (ELEM(NULL, id, adt)) { + BKE_report(reports, RPT_ERROR, "No ID-Block and/Or AnimData to delete keyframe from"); + return 0; + } + + /* validate pointer first - exit if failure */ + RNA_id_pointer_create(id, &id_ptr); + if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { + BKE_reportf(reports, RPT_ERROR, "Could not clear keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", id->name, rna_path); + return 0; + } + + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! + * so 'add' var must be 0 + */ + if (act == NULL) { + /* if no action is provided, use the default one attached to this ID-block + * - if it doesn't exist, then we're out of options... + */ + if (adt->action) { + act = adt->action; + } + else { + BKE_reportf(reports, RPT_ERROR, "No Action to delete keyframes from for ID = %s\n", id->name); + return 0; + } + } + + /* key entire array convenience method */ + if (array_index == -1) { + array_index = 0; + array_index_max = RNA_property_array_length(&ptr, prop); + + /* for single properties, increase max_index so that the property itself gets included, + * but don't do this for standard arrays since that can cause corruption issues + * (extra unused curves) + */ + if (array_index_max == array_index) + array_index_max++; + } + + /* will only loop once unless the array index was -1 */ + for (; array_index < array_index_max; array_index++) { + FCurve *fcu = verify_fcurve(act, group, &ptr, rna_path, array_index, 0); + + /* check if F-Curve exists and/or whether it can be edited */ + if (fcu == NULL) + continue; + + if ( (fcu->flag & FCURVE_PROTECTED) || ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) ) { + if (G.debug & G_DEBUG) + printf("WARNING: not deleting keyframe for locked F-Curve\n"); + continue; + } + + ANIM_fcurve_delete_from_animdata(NULL, adt, fcu); + + /* return success */ + ret++; + } + + /* return success/failure */ + return ret; +} + /* ******************************************* */ /* KEYFRAME MODIFICATION */ @@ -1584,6 +1669,78 @@ void ANIM_OT_keyframe_delete_button(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyframes from all elements of the array"); } + +/* Clear Key Button Operator ------------------------ */ + +static int clear_key_button_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop = NULL; + char *path; + short success = 0; + int a, index, length, all = RNA_boolean_get(op->ptr, "all"); + + /* try to insert keyframe using property retrieved from UI */ + uiContextActiveProperty(C, &ptr, &prop, &index); + + if (ptr.id.data && ptr.data && prop) { + path = RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + if (all) { + length = RNA_property_array_length(&ptr, prop); + + if (length) index = 0; + else length = 1; + } + else + length = 1; + + for (a = 0; a < length; a++) + success += clear_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index + a, 0); + + MEM_freeN(path); + } + else if (G.debug & G_DEBUG) + printf("Button Clear-Key: no path to property\n"); + } + else if (G.debug & G_DEBUG) { + printf("ptr.data = %p, prop = %p\n", (void *)ptr.data, (void *)prop); + } + + + if (success) { + /* send updates */ + uiContextAnimUpdate(C); + + DAG_ids_flush_update(bmain, 0); + + /* send notifiers that keyframes have been changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + } + + return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void ANIM_OT_keyframe_clear_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Keyframe (Buttons)"; + ot->idname = "ANIM_OT_keyframe_clear_button"; + ot->description = "Clear all keyframes on the currently active property"; + + /* callbacks */ + ot->exec = clear_key_button_exec; + ot->poll = modify_key_op_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Clear keyframes from all elements of the array"); +} + /* ******************************************* */ /* AUTO KEYFRAME */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 3099fcb2b40..5d62ef768d2 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -212,6 +212,12 @@ void ui_but_anim_delete_keyframe(bContext *C) WM_operator_name_call(C, "ANIM_OT_keyframe_delete_button", WM_OP_INVOKE_DEFAULT, NULL); } +void ui_but_anim_clear_keyframe(bContext *C) +{ + /* this operator calls uiContextActiveProperty */ + WM_operator_name_call(C, "ANIM_OT_keyframe_clear_button", WM_OP_INVOKE_DEFAULT, NULL); +} + void ui_but_anim_add_driver(bContext *C) { /* this operator calls uiContextActiveProperty */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 0a9665ffc15..91b3b3ea622 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -4474,6 +4474,19 @@ static int ui_but_menu(bContext *C, uiBut *but) ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); } + if (but->flag & UI_BUT_ANIMATED) { + if (length) { + uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"), + ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1); + uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"), + ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 0); + } + else { + uiItemBooleanO(layout, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"), + ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 0); + } + } + /* Drivers */ if (but->flag & UI_BUT_DRIVEN) { uiItemS(layout); @@ -4687,11 +4700,18 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event) ui_but_drop(C, event, but, data); } /* handle keyframing */ - else if (event->type == IKEY && !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) { - if (event->alt) - ui_but_anim_delete_keyframe(C); - else + else if (event->type == IKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey) && event->val == KM_PRESS) { + if (event->alt) { + if (event->shift) { + ui_but_anim_clear_keyframe(C); + } + else { + ui_but_anim_delete_keyframe(C); + } + } + else { ui_but_anim_insert_keyframe(C); + } ED_region_tag_redraw(CTX_wm_region(C)); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 1f88db033a4..c6787b4c554 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -508,6 +508,7 @@ void ui_but_add_shortcut(uiBut *but, const char *key_str, const short do_strip); void ui_but_anim_flag(uiBut *but, float cfra); void ui_but_anim_insert_keyframe(struct bContext *C); void ui_but_anim_delete_keyframe(struct bContext *C); +void ui_but_anim_clear_keyframe(struct bContext *C); void ui_but_anim_add_driver(struct bContext *C); void ui_but_anim_remove_driver(struct bContext *C); void ui_but_anim_copy_driver(struct bContext *C); |