2.5 - Groundwork for Adding/Removing Drivers
Drivers can now be Added/Removed from buttons using the D/Alt-D hotkeys, and also through the menu. Driver settings (i.e. the target) are not set by default. To set those, go to the Graph Editor (see notes). Notes: * Buildsystem maintainers - I've added a new file "editors/animation/drivers.c" * Widget colours for the driven-setting indications are needed * To see the new drivers, go into Graph Editor -> "Drivers" mode. Currently, there's a little bug there which prevents editing of the new drivers.
This commit is contained in:
@@ -386,6 +386,9 @@ void ED_operatortypes_anim(void)
|
||||
WM_operatortype_append(ANIM_OT_delete_keyframe_button);
|
||||
WM_operatortype_append(ANIM_OT_delete_keyframe_old); // xxx remove?
|
||||
|
||||
WM_operatortype_append(ANIM_OT_add_driver_button);
|
||||
WM_operatortype_append(ANIM_OT_remove_driver_button);
|
||||
|
||||
WM_operatortype_append(ANIM_OT_keyingset_add_new);
|
||||
WM_operatortype_append(ANIM_OT_keyingset_add_destination);
|
||||
}
|
||||
|
||||
289
source/blender/editors/animation/drivers.c
Normal file
289
source/blender/editors/animation/drivers.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/* Testing code for 2.5 animation system
|
||||
* Copyright 2009, Joshua Leung
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_dynstr.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_key.h"
|
||||
#include "BKE_material.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_util.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
/* ************************************************** */
|
||||
/* Animation Data Validation */
|
||||
|
||||
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
|
||||
* for the given Animation Data block. This assumes that all the destinations are valid.
|
||||
*/
|
||||
FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
|
||||
{
|
||||
AnimData *adt;
|
||||
FCurve *fcu;
|
||||
|
||||
/* sanity checks */
|
||||
if ELEM(NULL, id, rna_path)
|
||||
return NULL;
|
||||
|
||||
/* init animdata if none available yet */
|
||||
adt= BKE_animdata_from_id(id);
|
||||
if ((adt == NULL) && (add))
|
||||
adt= BKE_id_add_animdata(id);
|
||||
if (adt == NULL) {
|
||||
/* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* try to find f-curve matching for this setting
|
||||
* - add if not found and allowed to add one
|
||||
* TODO: add auto-grouping support? how this works will need to be resolved
|
||||
*/
|
||||
fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
|
||||
|
||||
if ((fcu == NULL) && (add)) {
|
||||
/* use default settings to make a F-Curve */
|
||||
fcu= MEM_callocN(sizeof(FCurve), "FCurve");
|
||||
|
||||
fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
|
||||
|
||||
/* store path - make copy, and store that */
|
||||
fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
|
||||
fcu->array_index= array_index;
|
||||
|
||||
/* add some new driver data */
|
||||
fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
|
||||
|
||||
/* just add F-Curve to end of driver list */
|
||||
BLI_addtail(&adt->drivers, fcu);
|
||||
}
|
||||
|
||||
/* return the F-Curve */
|
||||
return fcu;
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* Driver Management API */
|
||||
|
||||
/* Main Driver Management API calls:
|
||||
* Add a new driver for the specified property on the given ID block
|
||||
*/
|
||||
short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short flag)
|
||||
{
|
||||
PointerRNA id_ptr, ptr;
|
||||
PropertyRNA *prop;
|
||||
FCurve *fcu;
|
||||
|
||||
/* 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)) {
|
||||
printf("Insert Key: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create F-Curve with Driver */
|
||||
fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
|
||||
|
||||
/* done */
|
||||
return (fcu != NULL);
|
||||
}
|
||||
|
||||
/* Main Driver Management API calls:
|
||||
* Remove the driver for the specified property on the given ID block (if available)
|
||||
*/
|
||||
short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
|
||||
{
|
||||
AnimData *adt;
|
||||
FCurve *fcu;
|
||||
|
||||
/* get F-Curve
|
||||
* Note: here is one of the places where we don't want new F-Curve + Driver added!
|
||||
* so 'add' var must be 0
|
||||
*/
|
||||
/* we don't check the validity of the path here yet, but it should be ok... */
|
||||
fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
|
||||
adt= BKE_animdata_from_id(id);
|
||||
|
||||
/* only continue if we have an driver to remove */
|
||||
if (adt && fcu) {
|
||||
/* remove F-Curve from driver stack, then free it */
|
||||
BLI_remlink(&adt->drivers, fcu);
|
||||
free_fcurve(fcu);
|
||||
|
||||
/* done successfully */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* failed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* UI-Button Interface */
|
||||
|
||||
/* Add Driver Button Operator ------------------------ */
|
||||
|
||||
static int add_driver_button_exec (bContext *C, wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
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 */
|
||||
memset(&ptr, 0, sizeof(PointerRNA));
|
||||
uiAnimContextProperty(C, &ptr, &prop, &index);
|
||||
|
||||
if (ptr.data && prop && RNA_property_animateable(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+= ANIM_add_driver(ptr.id.data, path, index+a, 0);
|
||||
|
||||
MEM_freeN(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
/* send updates */
|
||||
ED_anim_dag_flush_update(C);
|
||||
|
||||
/* for now, only send ND_KEYS for KeyingSets */
|
||||
WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
|
||||
}
|
||||
|
||||
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void ANIM_OT_add_driver_button (wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Add Driver";
|
||||
ot->idname= "ANIM_OT_add_driver_button";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec= add_driver_button_exec;
|
||||
//op->poll= ???
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "all", 1, "All", "Insert a keyframe for all element of the array.");
|
||||
}
|
||||
|
||||
/* Remove Driver Button Operator ------------------------ */
|
||||
|
||||
static int remove_driver_button_exec (bContext *C, wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
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 */
|
||||
memset(&ptr, 0, sizeof(PointerRNA));
|
||||
uiAnimContextProperty(C, &ptr, &prop, &index);
|
||||
|
||||
if (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+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
|
||||
|
||||
MEM_freeN(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (success) {
|
||||
/* send updates */
|
||||
ED_anim_dag_flush_update(C);
|
||||
|
||||
/* for now, only send ND_KEYS for KeyingSets */
|
||||
WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
|
||||
}
|
||||
|
||||
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void ANIM_OT_remove_driver_button (wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Remove Driver";
|
||||
ot->idname= "ANIM_OT_remove_driver_button";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec= remove_driver_button_exec;
|
||||
//op->poll= ???
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna, "all", 1, "All", "Delete keyfames from all elements of the array.");
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
@@ -825,7 +825,7 @@ short deletekey (ID *id, const char group[], const char rna_path[], int array_in
|
||||
fcu= verify_fcurve(id, group, rna_path, array_index, 0);
|
||||
adt= BKE_animdata_from_id(id);
|
||||
|
||||
/* only continue if we have an ipo-curve to remove keyframes from */
|
||||
/* only continue if we have an F-Curve to remove keyframes from */
|
||||
if (adt && adt->action && fcu) {
|
||||
bAction *act= adt->action;
|
||||
short found = -1;
|
||||
|
||||
@@ -95,10 +95,25 @@ void ANIM_OT_delete_keyframe_menu(struct wmOperatorType *ot); // xxx unimplement
|
||||
void ANIM_OT_delete_keyframe_old(struct wmOperatorType *ot); // xxx rename and keep?
|
||||
|
||||
/* Keyframe managment operators for UI buttons. */
|
||||
|
||||
void ANIM_OT_insert_keyframe_button(struct wmOperatorType *ot);
|
||||
void ANIM_OT_delete_keyframe_button(struct wmOperatorType *ot);
|
||||
|
||||
/* ************ Drivers ********************** */
|
||||
|
||||
/* Main Driver Management API calls:
|
||||
* Add a new driver for the specified property on the given ID block
|
||||
*/
|
||||
short ANIM_add_driver (struct ID *id, const char rna_path[], int array_index, short flag);
|
||||
|
||||
/* Main Driver Management API calls:
|
||||
* Remove the driver for the specified property on the given ID block (if available)
|
||||
*/
|
||||
short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag);
|
||||
|
||||
/* Driver management operators for UI buttons */
|
||||
void ANIM_OT_add_driver_button(struct wmOperatorType *ot);
|
||||
void ANIM_OT_remove_driver_button(struct wmOperatorType *ot);
|
||||
|
||||
/* ************ Auto-Keyframing ********************** */
|
||||
/* Notes:
|
||||
* - All the defines for this (User-Pref settings and Per-Scene settings)
|
||||
|
||||
@@ -133,6 +133,7 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle;
|
||||
#define UI_NO_HILITE (1<<19)
|
||||
#define UI_BUT_ANIMATED (1<<20)
|
||||
#define UI_BUT_ANIMATED_KEY (1<<21)
|
||||
#define UI_BUT_DRIVEN (1<<22)
|
||||
|
||||
|
||||
/* Button types, bits stored in 1 value... and a short even!
|
||||
|
||||
@@ -27,28 +27,41 @@
|
||||
|
||||
void ui_but_anim_flag(uiBut *but, float cfra)
|
||||
{
|
||||
but->flag &= ~(UI_BUT_ANIMATED|UI_BUT_ANIMATED_KEY);
|
||||
but->flag &= ~(UI_BUT_ANIMATED|UI_BUT_ANIMATED_KEY|UI_BUT_DRIVEN);
|
||||
|
||||
if(but->rnaprop && but->rnapoin.id.data) {
|
||||
AnimData *adt= BKE_animdata_from_id(but->rnapoin.id.data);
|
||||
FCurve *fcu;
|
||||
char *path;
|
||||
|
||||
if(adt && adt->action && adt->action->curves.first) {
|
||||
/* XXX this function call can become a performance bottleneck */
|
||||
path= RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
|
||||
|
||||
if(path) {
|
||||
fcu= list_find_fcurve(&adt->action->curves, path, but->rnaindex);
|
||||
|
||||
if(fcu) {
|
||||
but->flag |= UI_BUT_ANIMATED;
|
||||
|
||||
if(on_keyframe_fcurve(fcu, cfra))
|
||||
but->flag |= UI_BUT_ANIMATED_KEY;
|
||||
if (adt) {
|
||||
if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) {
|
||||
/* XXX this function call can become a performance bottleneck */
|
||||
path= RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
|
||||
|
||||
if (path) {
|
||||
/* animation takes priority over drivers */
|
||||
if (adt->action && adt->action->curves.first) {
|
||||
fcu= list_find_fcurve(&adt->action->curves, path, but->rnaindex);
|
||||
|
||||
if (fcu) {
|
||||
but->flag |= UI_BUT_ANIMATED;
|
||||
|
||||
if (on_keyframe_fcurve(fcu, cfra))
|
||||
but->flag |= UI_BUT_ANIMATED_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
/* if not animated, check if driven */
|
||||
if ((but->flag & UI_BUT_ANIMATED)==0 && (adt->drivers.first)) {
|
||||
fcu= list_find_fcurve(&adt->drivers, path, but->rnaindex);
|
||||
|
||||
if (fcu)
|
||||
but->flag |= UI_BUT_DRIVEN;
|
||||
}
|
||||
|
||||
MEM_freeN(path);
|
||||
}
|
||||
|
||||
MEM_freeN(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +99,19 @@ void ui_but_anim_delete_keyframe(bContext *C)
|
||||
WM_operator_name_call(C, "ANIM_OT_delete_keyframe_button", WM_OP_INVOKE_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
void ui_but_anim_add_driver(bContext *C)
|
||||
{
|
||||
/* this operator calls uiAnimContextProperty above */
|
||||
WM_operator_name_call(C, "ANIM_OT_add_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
void ui_but_anim_remove_driver(bContext *C)
|
||||
{
|
||||
/* this operator calls uiAnimContextProperty above */
|
||||
WM_operator_name_call(C, "ANIM_OT_remove_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
// TODO: refine the logic for adding/removing drivers...
|
||||
void ui_but_anim_menu(bContext *C, uiBut *but)
|
||||
{
|
||||
uiMenuItem *head;
|
||||
@@ -100,18 +126,28 @@ void ui_but_anim_menu(bContext *C, uiBut *but)
|
||||
if(length) {
|
||||
uiMenuItemBooleanO(head, "Delete Keyframes", 0, "ANIM_OT_delete_keyframe_button", "all", 1);
|
||||
uiMenuItemBooleanO(head, "Delete Single Keyframe", 0, "ANIM_OT_delete_keyframe_button", "all", 0);
|
||||
|
||||
uiMenuItemBooleanO(head, "Remove Driver", 0, "ANIM_OT_remove_driver_button", "all", 1);
|
||||
uiMenuItemBooleanO(head, "Remove Single Driver", 0, "ANIM_OT_remove_driver_button", "all", 0);
|
||||
}
|
||||
else {
|
||||
uiMenuItemBooleanO(head, "Delete Keyframe", 0, "ANIM_OT_delete_keyframe_button", "all", 0);
|
||||
|
||||
uiMenuItemBooleanO(head, "Remove Driver", 0, "ANIM_OT_remove_driver_button", "all", 0);
|
||||
}
|
||||
}
|
||||
else if(RNA_property_animateable(&but->rnapoin, but->rnaprop)) {
|
||||
if(length) {
|
||||
uiMenuItemBooleanO(head, "Insert Keyframes", 0, "ANIM_OT_insert_keyframe_button", "all", 1);
|
||||
uiMenuItemBooleanO(head, "Insert Single Keyframe", 0, "ANIM_OT_insert_keyframe_button", "all", 0);
|
||||
|
||||
uiMenuItemBooleanO(head, "Add Driver", 0, "ANIM_OT_add_driver_button", "all", 1);
|
||||
uiMenuItemBooleanO(head, "Add Single Driver", 0, "ANIM_OT_add_driver_button", "all", 0);
|
||||
}
|
||||
else {
|
||||
uiMenuItemBooleanO(head, "Insert Keyframe", 0, "ANIM_OT_insert_keyframe_button", "all", 0);
|
||||
|
||||
uiMenuItemBooleanO(head, "Add Driver", 0, "ANIM_OT_add_driver_button", "all", 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2610,6 +2610,17 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
|
||||
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
/* handle driver adding */
|
||||
else if(event->type == DKEY && event->val == KM_PRESS) {
|
||||
if(event->alt)
|
||||
ui_but_anim_remove_driver(C);
|
||||
else
|
||||
ui_but_anim_add_driver(C);
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
/* handle menu */
|
||||
else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) {
|
||||
ui_but_anim_menu(C, but);
|
||||
|
||||
@@ -393,6 +393,8 @@ void uiStyleExit(void);
|
||||
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_add_driver(struct bContext *C);
|
||||
void ui_but_anim_remove_driver(struct bContext *C);
|
||||
void ui_but_anim_menu(struct bContext *C, uiBut *but);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1053,6 +1053,8 @@ static void widget_state(uiWidgetType *wt, int state)
|
||||
QUATCOPY(wt->wcol.inner, wt->wcol.inner_key_sel)
|
||||
else if(state & UI_BUT_ANIMATED)
|
||||
QUATCOPY(wt->wcol.inner, wt->wcol.inner_anim_sel)
|
||||
//else if(state & UI_BUT_DRIVEN)
|
||||
// QUATCOPY(wt->wcol.inner, wt->wcol.inner_driven_sel)
|
||||
else
|
||||
QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user