From 69ee6c986657bf0d6bf631277751d24e72d76bac Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 15 Apr 2016 20:04:07 +1200 Subject: Drivers Editing: Added "Copy/Paste" buttons beside "Add Variable" for copying all variables from one driver to another This was a feature request from a few years back (IIRC from ZanQdo?) to make it easier to reuse one set of driver variables across several different drivers. Dev Notes: * Finally it's done! All that trouble for two little buttons. * Grr... cmake... grrr! --- source/blender/editors/animation/CMakeLists.txt | 4 + source/blender/editors/animation/drivers.c | 116 ++++++++++++++++++- source/blender/editors/include/ED_keyframing.h | 14 +++ source/blender/editors/space_graph/graph_buttons.c | 30 +++-- source/blender/editors/space_graph/graph_edit.c | 128 +++++++++++++++++++++ source/blender/editors/space_graph/graph_intern.h | 5 + source/blender/editors/space_graph/graph_ops.c | 4 + 7 files changed, 291 insertions(+), 10 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index 473b0e6bc5a..1bf1bb2a474 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -59,6 +59,10 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() +if(WITH_PYTHON) + add_definitions(-DWITH_PYTHON) +endif() + add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 4ddf37aa3a1..27bed693619 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -600,7 +600,7 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a /* create Driver F-Curve, but without data which will be copied across... */ fcu = verify_driver_fcurve(id, rna_path, array_index, -1); - + if (fcu) { /* copy across the curve data from the buffer curve * NOTE: this step needs care to not miss new settings @@ -624,6 +624,120 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a return (fcu != NULL); } +/* ************************************************** */ +/* Driver Management API - Copy/Paste Driver Variables */ + +/* Copy/Paste Buffer for Driver Variables... */ +static ListBase driver_vars_copybuf = {NULL, NULL}; + +/* This function frees any MEM_calloc'ed copy/paste buffer data */ +void ANIM_driver_vars_copybuf_free(void) +{ + /* Free the driver variables kept in the buffer */ + if (driver_vars_copybuf.first) { + /* We use a dummy driver here, as the variable freeing code assumes there's a driver */ + ChannelDriver dummy_driver = {{NULL}}; + dummy_driver.variables = driver_vars_copybuf; + + /* Free variables (and any data they use) */ + DriverVar *dvar, *dvarn; + for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable(&driver_vars_copybuf, dvar); + } + } + + BLI_listbase_clear(&driver_vars_copybuf); +} + +/* Checks if there are driver variables in the copy/paste buffer */ +bool ANIM_driver_vars_can_paste(void) +{ + return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); +} + +/* -------------------------------------------------- */ + +/* Copy the given driver's variables to the buffer */ +bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu) +{ + /* sanity checks */ + if (ELEM(NULL, fcu, fcu->driver)) { + BKE_report(reports, RPT_ERROR, "No driver to copy variables from"); + return false; + } + + if (BLI_listbase_is_empty(&fcu->driver->variables)) { + BKE_report(reports, RPT_ERROR, "Driver has no variables to copy"); + return false; + } + + /* clear buffer */ + ANIM_driver_vars_copybuf_free(); + + /* copy over the variables */ + driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables); + + return (BLI_listbase_is_empty(&driver_vars_copybuf) == false); +} + +/* Paste the variables in the buffer to the given FCurve */ +bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace) +{ + ChannelDriver *driver = (fcu) ? fcu->driver : NULL; + ListBase tmp_list = {NULL, NULL}; + + /* sanity checks */ + if (BLI_listbase_is_empty(&driver_vars_copybuf)) { + BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste"); + return false; + } + + if (ELEM(NULL, fcu, fcu->driver)) { + BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver"); + return false; + } + + /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */ + driver_variables_copy(&tmp_list, &driver_vars_copybuf); + + /* 2) Prepare destination array */ + if (replace) { + DriverVar *dvar, *dvarn; + + /* Free all existing vars first - We aren't retaining anything */ + for (dvar = driver->variables.first; dvar; dvar = dvarn) { + dvarn = dvar->next; + driver_free_variable_ex(driver, dvar); + } + + BLI_listbase_clear(&driver->variables); + } + + /* 3) Add new vars */ + if (driver->variables.last) { + DriverVar *last = driver->variables.last; + DriverVar *first = tmp_list.first; + + last->next = first; + first->prev = last; + + driver->variables.last = tmp_list.last; + } + else { + driver->variables.first = tmp_list.first; + driver->variables.last = tmp_list.last; + } + +#ifdef WITH_PYTHON + /* since driver variables are cached, the expression needs re-compiling too */ + if (driver->type == DRIVER_TYPE_PYTHON) + driver->flag |= DRIVER_FLAG_RENAMEVAR; +#endif + + return true; +} + /* ************************************************** */ /* UI-Button Interface */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 9a411975880..81e2558e765 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -291,6 +291,9 @@ bool ANIM_remove_driver(struct ReportList *reports, struct ID *id, const char rn /* Clear copy-paste buffer for drivers */ void ANIM_drivers_copybuf_free(void); +/* Clear copy-paste buffer for driver variable sets */ +void ANIM_driver_vars_copybuf_free(void); + /* -------- */ /* Returns whether there is a driver in the copy/paste buffer to paste */ @@ -307,6 +310,17 @@ bool ANIM_copy_driver(struct ReportList *reports, struct ID *id, const char rna_ */ bool ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag); +/* -------- */ + +/* Checks if there are driver variables in the copy/paste buffer */ +bool ANIM_driver_vars_can_paste(void); + +/* Copy the given driver's variables to the buffer */ +bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu); + +/* Paste the variables in the buffer to the given FCurve */ +bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace); + /* ************ Auto-Keyframing ********************** */ /* Notes: * - All the defines for this (User-Pref settings and Per-Scene settings) diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index f8b081eda20..5846a439b3c 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -516,7 +516,7 @@ static void driver_delete_var_cb(bContext *UNUSED(C), void *driver_v, void *dvar DriverVar *dvar = (DriverVar *)dvar_v; /* remove the active variable */ - driver_free_variable(driver, dvar); + driver_free_variable_ex(driver, dvar); } /* callback to report why a driver variable is invalid */ @@ -825,14 +825,26 @@ static void graph_panel_drivers(const bContext *C, Panel *pa) uiItemL(row, valBuf, ICON_NONE); } - /* add driver variables */ - col = uiLayoutColumn(pa->layout, false); - block = uiLayoutGetBlock(col); - but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"), - 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y, - NULL, 0.0, 0.0, 0, 0, - TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly")); - UI_but_func_set(but, driver_add_var_cb, driver, NULL); + /* add/copy/paste driver variables */ + { + uiLayout *row; + + /* add driver variable */ + row = uiLayoutRow(pa->layout, false); + block = uiLayoutGetBlock(row); + but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"), + 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y, + NULL, 0.0, 0.0, 0, 0, + TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly")); + UI_but_func_set(but, driver_add_var_cb, driver, NULL); + + /* copy/paste (as sub-row) */ + row = uiLayoutRow(row, true); + block = uiLayoutGetBlock(row); + + uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy"); + uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste"); + } /* loop over targets, drawing them */ for (dvar = driver->variables.first; dvar; dvar = dvar->next) { diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index dd2ec2401a5..a54b7e141f3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -54,6 +54,7 @@ #include "BLT_translation.h" +#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_nla.h" @@ -2610,3 +2611,130 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot) } /* ************************************************************************** */ +/* Drivers */ + +/* ******************** Copy Driver Vars Operator *********************** */ + +static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + bAnimListElem *ale; + bool ok = false; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* clear buffer first */ + ANIM_driver_vars_copybuf_free(); + + /* get the active F-Curve */ + ale = get_active_fcurve_channel(&ac); + + /* if this exists, call the copy driver vars API function */ + if (ale && ale->data) { + FCurve *fcu = (FCurve *)ale->data; + + ok = ANIM_driver_vars_copy(op->reports, fcu); + + /* free temp data now */ + MEM_freeN(ale); + } + + /* successful or not? */ + if (ok == 0) + return OPERATOR_CANCELLED; + else + return OPERATOR_FINISHED; +} + +void GRAPH_OT_driver_variables_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Copy Driver Variables"; + ot->idname = "GRAPH_OT_driver_variables_copy"; + ot->description = "Copy the driver variables of the active F-Curve"; + + /* api callbacks */ + ot->exec = graph_driver_vars_copy_exec; + ot->poll = graphop_active_fcurve_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ******************** Paste Driver Vars Operator *********************** */ + +static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + const bool replace = RNA_boolean_get(op->ptr, "replace"); + bool ok = false; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* paste modifiers */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->data; + bool paste_ok; + + printf("pasting vars to %p -> %p\n", fcu, fcu->driver); + paste_ok = ANIM_driver_vars_paste(op->reports, fcu, replace); + + if (paste_ok) { + //ale->update |= ANIM_UPDATE_DEPS; + printf("now we have: %d vars\n", BLI_listbase_count(&fcu->driver->variables)); + ok = true; + } + } + + // XXX: something causes a crash after adding the copies (to empty list), if we do an update immediately + if (ok) { + DAG_relations_tag_update(CTX_data_main(C)); + //ANIM_animdata_update(&ac, &anim_data); + } + ANIM_animdata_freelist(&anim_data); + + /* successful or not? */ + if (ok) { + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Paste Driver Variables"; + ot->idname = "GRAPH_OT_driver_variables_paste"; + ot->description = "Add copied driver variables to the active driver"; + + /* api callbacks */ + ot->exec = graph_driver_vars_paste_exec; + ot->poll = graphop_active_fcurve_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active F-Curve"); + RNA_def_boolean(ot->srna, "replace", false, "Replace Existing", + "Replace existing F-Modifiers, instead of just appending to the end of the existing list"); +} + +/* ************************************************************************** */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index a478a86a5e2..b6b711e129f 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -148,6 +148,11 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot); /* ----------- */ +void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot); +void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot); + +/* ----------- */ + void GRAPH_OT_ghost_curves_create(struct wmOperatorType *ot); void GRAPH_OT_ghost_curves_clear(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 59215531ac0..7ffa8250067 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -458,6 +458,10 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_fmodifier_add); WM_operatortype_append(GRAPH_OT_fmodifier_copy); WM_operatortype_append(GRAPH_OT_fmodifier_paste); + + /* Drivers */ + WM_operatortype_append(GRAPH_OT_driver_variables_copy); + WM_operatortype_append(GRAPH_OT_driver_variables_paste); } void ED_operatormacros_graph(void) -- cgit v1.2.3