Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-07-31 18:42:03 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-08-04 13:58:15 +0300
commit47335b4e61db11e1ee2e38f421dc86fa3c3dd375 (patch)
treeffc2ccfed4d77158ce42a6f7151693f39e7160b3
parenta2fe386153ee976bf5b687257f117ca4efb1ef8f (diff)
Add a new Copy As Driver context menu option for properties.
It is a very common need to create drivers that set the value of a property to the value of some other property, but it currently requires multiple actions: Copy Data Path on the input property, adding a driver to the output property, selecting the input ID reference, and pasting the path. This adds a new Copy As Driver context menu option, which creates a complete driver in the clipboard that reads the current property, so all that remains is to paste it to the output property. It is also possible to paste just the new driver variable into an existing driver to combine multiple inputs. Reviewers: brecht, billreynish Differential Revision: https://developer.blender.org/D5382
-rw-r--r--source/blender/editors/animation/drivers.c136
-rw-r--r--source/blender/editors/include/ED_keyframing.h8
-rw-r--r--source/blender/editors/interface/interface_context_menu.c7
-rw-r--r--source/blender/editors/interface/interface_ops.c81
4 files changed, 186 insertions, 46 deletions
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 7ca0f95d6c4..935d11a388f 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include "MEM_guardedalloc.h"
@@ -95,56 +96,65 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
if ((fcu == NULL) && (add)) {
/* use default settings to make a F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu = alloc_driver_fcurve(rna_path, array_index, add);
- fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ /* just add F-Curve to end of driver list */
+ BLI_addtail(&adt->drivers, fcu);
+ }
- /* store path - make copy, and store that */
- fcu->rna_path = BLI_strdup(rna_path);
- fcu->array_index = array_index;
-
- /* If add is negative, don't init this data yet,
- * since it will be filled in by the pasted driver. */
- if (add > 0) {
- BezTriple *bezt;
- size_t i;
-
- /* add some new driver data */
- fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
-
- /* F-Modifier or Keyframes? */
- // FIXME: replace these magic numbers with defines
- if (add == 2) {
- /* Python API Backwards compatibility hack:
- * Create FModifier so that old scripts won't break
- * for now before 2.7 series -- (September 4, 2013)
- */
- add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
- }
- else {
- /* add 2 keyframes so that user has something to work with
- * - These are configured to 0,0 and 1,1 to give a 1-1 mapping
- * which can be easily tweaked from there.
- */
- insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ /* return the F-Curve */
+ return fcu;
+}
- /* configure this curve to extrapolate */
- for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
- bezt->h1 = bezt->h2 = HD_VECT;
- }
+struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add)
+{
+ FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
- fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
- calchandles_fcurve(fcu);
- }
+ fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
+ fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+
+ /* store path - make copy, and store that */
+ if (rna_path) {
+ fcu->rna_path = BLI_strdup(rna_path);
+ }
+ fcu->array_index = array_index;
+
+ /* If add is negative, don't init this data yet,
+ * since it will be filled in by the pasted driver. */
+ if (add > 0) {
+ BezTriple *bezt;
+ size_t i;
+
+ /* add some new driver data */
+ fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
+
+ /* F-Modifier or Keyframes? */
+ // FIXME: replace these magic numbers with defines
+ if (add == 2) {
+ /* Python API Backwards compatibility hack:
+ * Create FModifier so that old scripts won't break
+ * for now before 2.7 series -- (September 4, 2013)
+ */
+ add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR, fcu);
}
+ else {
+ /* add 2 keyframes so that user has something to work with
+ * - These are configured to 0,0 and 1,1 to give a 1-1 mapping
+ * which can be easily tweaked from there.
+ */
+ insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- /* just add F-Curve to end of driver list */
- BLI_addtail(&adt->drivers, fcu);
+ /* configure this curve to extrapolate */
+ for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
+ bezt->h1 = bezt->h2 = HD_VECT;
+ }
+
+ fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
+ calchandles_fcurve(fcu);
+ }
}
- /* return the F-Curve */
return fcu;
}
@@ -834,6 +844,48 @@ bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
return true;
}
+/* -------------------------------------------------- */
+
+/* Create a driver & variable that reads the specified property,
+ * and store it in the buffers for Paste Driver and Paste Variables. */
+void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name)
+{
+ /* Clear copy/paste buffer first (for consistency with other copy/paste buffers). */
+ ANIM_drivers_copybuf_free();
+ ANIM_driver_vars_copybuf_free();
+
+ /* Create a dummy driver F-Curve. */
+ FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1);
+ ChannelDriver *driver = fcu->driver;
+
+ /* Create a variable. */
+ DriverVar *var = driver_add_new_variable(driver);
+ DriverTarget *target = &var->targets[0];
+
+ target->idtype = GS(target_id->name);
+ target->id = target_id;
+ target->rna_path = MEM_dupallocN(target_path);
+
+ /* Set the variable name. */
+ if (var_name) {
+ BLI_strncpy(var->name, var_name, sizeof(var->name));
+
+ /* Sanitize the name. */
+ for (int i = 0; var->name[i]; i++) {
+ if (!(i > 0 ? isalnum(var->name[i]) : isalpha(var->name[i]))) {
+ var->name[i] = '_';
+ }
+ }
+ }
+
+ BLI_strncpy(driver->expression, var->name, sizeof(driver->expression));
+
+ /* Store the driver into the copy/paste buffers. */
+ channeldriver_copypaste_buf = fcu;
+
+ driver_variables_copy(&driver_vars_copybuf, &driver->variables);
+}
+
/* ************************************************** */
/* UI-Button Interface */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 8f197fa9afe..bbeeeade822 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -320,6 +320,8 @@ struct FCurve *verify_driver_fcurve(struct ID *id,
const int array_index,
short add);
+struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add);
+
/* -------- */
/* Main Driver Management API calls:
@@ -399,6 +401,12 @@ 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);
+/* -------- */
+
+/* Create a driver & variable that reads the specified property,
+ * and store it in the buffers for Paste Driver and Paste Variables. */
+void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const char *var_name);
+
/* ************ Auto-Keyframing ********************** */
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 7cec8af46de..88fe8704082 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -899,6 +899,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
ICON_NONE,
"UI_OT_copy_data_path_button");
+ if (ptr->id.data && ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
+ uiItemO(layout,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"),
+ ICON_NONE,
+ "UI_OT_copy_as_driver_button");
+ }
+
uiItemS(layout);
if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index f2b2a478ba9..f5a894d7620 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -65,6 +65,9 @@
#include "ED_object.h"
#include "ED_paint.h"
+/* for Copy As Driver */
+#include "ED_keyframing.h"
+
/* only for UI_OT_editsource */
#include "ED_screen.h"
#include "BKE_main.h"
@@ -153,23 +156,92 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static bool copy_python_command_button_poll(bContext *C)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy As Driver Operator
+ * \{ */
+
+static bool copy_as_driver_button_poll(bContext *C)
{
- uiBut *but = UI_context_active_but_get(C);
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ char *path;
+ int index;
- if (but && (but->optype != NULL)) {
- return 1;
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop &&
+ ELEM(RNA_property_type(prop), PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
+ path = RNA_path_from_ID_to_property(&ptr, prop);
+
+ if (path) {
+ MEM_freeN(path);
+ return 1;
+ }
}
return 0;
}
+static int copy_as_driver_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ /* try to create driver using property retrieved from UI */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop) {
+ int dim = RNA_property_array_dimension(&ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property_index(&ptr, prop, dim, index);
+
+ if (path) {
+ ANIM_copy_as_driver(ptr.id.data, path, RNA_property_identifier(prop));
+ MEM_freeN(path);
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy As New Driver";
+ ot->idname = "UI_OT_copy_as_driver_button";
+ ot->description =
+ "Create a new driver with this property as input, and copy it to the "
+ "clipboard. Use Paste Driver to add it to the target property, or Paste "
+ "Driver Variables to extend an existing driver";
+
+ /* callbacks */
+ ot->exec = copy_as_driver_button_exec;
+ ot->poll = copy_as_driver_button_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Copy Python Command Operator
* \{ */
+static bool copy_python_command_button_poll(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but && (but->optype != NULL)) {
+ return 1;
+ }
+
+ return 0;
+}
+
static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op))
{
uiBut *but = UI_context_active_but_get(C);
@@ -1668,6 +1740,7 @@ static void UI_OT_drop_color(wmOperatorType *ot)
void ED_operatortypes_ui(void)
{
WM_operatortype_append(UI_OT_copy_data_path_button);
+ WM_operatortype_append(UI_OT_copy_as_driver_button);
WM_operatortype_append(UI_OT_copy_python_command_button);
WM_operatortype_append(UI_OT_reset_default_button);
WM_operatortype_append(UI_OT_assign_default_button);