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:
2009-04-10 13:08:12 +00:00
parent be8b7ead51
commit 6593bbaca2
9 changed files with 376 additions and 17 deletions

View File

@@ -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);
}

View 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.");
}
/* ************************************************** */

View File

@@ -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;

View File

@@ -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)

View File

@@ -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!

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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)