Drivers Setup: Expose all mapping types for creating drivers

* This includes the "manually create" modes, which correspond to the previous behaviour
  for setting up drivers. This is necessary when the current screen layout is not
  well suited to having multiple property editors open (e.g. small screen or heavily
  subdivided screen).

* Only the modes relevant for the current property type (i.e. array vs single)
  will be shown

* The "Add Driver" entries in the RMB context menu have now been replaced by a
  submenu which will list all the available mapping types.

* NOTE: The code for the ANIM_OT_button_driver_add() operator is perhaps a bit hairy.
  However, it currently allows us to have the desired behaviour. It can always get
  cleaned up later though.
This commit is contained in:
2016-03-30 03:01:27 +13:00
parent 3237ae2855
commit deffd4352b
4 changed files with 143 additions and 46 deletions

View File

@@ -155,24 +155,6 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* ************************************************** */
/* Driver Management API */
/* Mapping Types enum for operators */
// XXX: These names need reviewing
EnumPropertyItem prop_driver_create_mapping_types[] = {
{CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", 0, "All from Target",
"Drive all components of this property using the target picked"},
{CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
"Drive this component of this property using the target picked"},
{CREATEDRIVER_MAPPING_N_N, "MATCH", 0, "Match Indices",
"Create drivers for each pair of corresponding elements"},
// XXX: for all vs just one?
{CREATEDRIVER_MAPPING_NONE, "NONE", 0, "Manually Create Later",
"Create driver without assigning any targets yet"},
{0, NULL, 0, NULL, NULL}
};
/* --------------------------------- */
/* Helper for ANIM_add_driver_with_target - Adds the actual driver */
static int add_driver_with_target(
ReportList *UNUSED(reports),
@@ -648,37 +630,144 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
/* ************************************************** */
/* UI-Button Interface */
/* Add Driver - Enum Defines ------------------------- */
/* Mapping Types enum for operators */
/* NOTE: Used by ANIM_OT_driver_button_add and UI_OT_eyedropper_driver */
// XXX: These names need reviewing
EnumPropertyItem prop_driver_create_mapping_types[] = {
{CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", 0, "All from Target",
"Drive all components of this property using the target picked"},
{CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
"Drive this component of this property using the target picked"},
{CREATEDRIVER_MAPPING_N_N, "MATCH", 0, "Match Indices",
"Create drivers for each pair of corresponding elements"},
{CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", 0, "Manually Create Later",
"Create drivers for all properites without assigning any targets yet"},
{CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)",
"Create driver for this property only and without assigning any targets yet"},
{0, NULL, 0, NULL, NULL}
};
/* Filtering callback for driver mapping types enum */
static EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, PointerRNA *UNUSED(owner_ptr), PropertyRNA *UNUSED(owner_prop), bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
int index;
int totitem = 0;
if (!C) /* needed for docs */
return prop_driver_create_mapping_types;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
const bool is_array = RNA_property_array_check(prop);
while (input->identifier) {
if (ELEM(input->value, CREATEDRIVER_MAPPING_1_1, CREATEDRIVER_MAPPING_NONE) || (is_array)) {
RNA_enum_item_add(&item, &totitem, input);
}
input++;
}
}
else {
/* We need at least this one! */
RNA_enum_items_add_value(&item, &totitem, input, CREATEDRIVER_MAPPING_NONE);
}
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
/* Add Driver Button Operator ------------------------ */
static int add_driver_button_exec(bContext *C, wmOperator *op)
static int add_driver_button_poll(bContext *C)
{
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
int ret = OPERATOR_CANCELLED;
/* this operator can only run if there's a property button active, and it can be animated */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
return (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop));
}
/* Wrapper for creating a driver without knowing what the targets will be yet (i.e. "manual/add later") */
static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_type)
{
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
int index;
int success = 0;
/* try to create driver using property retrieved from UI */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL)
index = -1;
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true);
PointerRNA op_ptr;
char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
WM_operator_properties_create_ptr(&op_ptr, ot);
if (all)
RNA_enum_set(&op_ptr, "mapping_type", CREATEDRIVER_MAPPING_1_N);
else
RNA_enum_set(&op_ptr, "mapping_type", CREATEDRIVER_MAPPING_1_1);
ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
WM_operator_properties_free(&op_ptr);
if (path) {
success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
MEM_freeN(path);
}
}
return ret;
if (success) {
/* send updates */
UI_context_update_anim_flag(C);
DAG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
return OPERATOR_FINISHED;
}
else {
return OPERATOR_CANCELLED;
}
}
static int add_driver_button_exec(bContext *C, wmOperator *op)
{
short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) {
/* Just create driver with no targets */
return add_driver_button_none(C, op, mapping_type);
}
else {
/* Create Driver using Eyedropper */
wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true);
/* XXX: We assume that it's fine to use the same set of properties, since they're actually the same... */
return WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, op->ptr);
}
}
/* Show menu or create drivers */
static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *prop;
if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && RNA_property_is_set(op->ptr, prop)) {
/* Mapping Type is Set - Directly go into creating drivers */
return add_driver_button_exec(C, op);
}
else {
/* Show menu */
// TODO: This should get filtered by the enum filter
return WM_menu_invoke(C, op, event);
}
}
void ANIM_OT_driver_button_add(wmOperatorType *ot)
@@ -689,14 +778,20 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot)
ot->description = "Add driver(s) for the property(s) connected represented by the highlighted button";
/* callbacks */
/* NOTE: No exec, as we need all these to use the current context info
* (especially the eyedropper, which is interactive)
*/
ot->invoke = add_driver_button_invoke;
ot->exec = add_driver_button_exec;
//op->poll = ??? // TODO: need to have some animatable property to do this
ot->poll = add_driver_button_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array");
ot->prop = RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
"Mapping Type", "Method used to match target and driven properties");
RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
}
/* Remove Driver Button Operator ------------------------ */

View File

@@ -240,7 +240,9 @@ typedef enum eCreateDriver_MappingTypes {
CREATEDRIVER_MAPPING_1_N = 0, /* 1 to Many - Use the specified index, and drive all elements with it */
CREATEDRIVER_MAPPING_1_1 = 1, /* 1 to 1 - Only for the specified index on each side */
CREATEDRIVER_MAPPING_N_N = 2, /* Many to Many - Match up the indices one by one (only for drivers on vectors/arrays) */
CREATEDRIVER_MAPPING_NONE = 3, /* None - Do not create driver with any targets; these will get added later instead, when more convenient */
CREATEDRIVER_MAPPING_NONE = 3, /* None (Single Prop) - Do not create driver with any targets; these will get added later instead */
CREATEDRIVER_MAPPING_NONE_ALL = 4, /* None (All Properties) - Do not create driver with any targets; these will get added later instead */
} eCreateDriver_MappingTypes;
/* RNA Enum of eCreateDriver_MappingTypes, for use by the appropriate operators */

View File

@@ -1231,7 +1231,7 @@ void UI_OT_eyedropper_driver(wmOperatorType *ot)
ot->poll = driverdropper_poll;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
/* properties */
RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,

View File

@@ -6719,14 +6719,14 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemS(layout);
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Driver"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 0);
uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
ICON_NONE);
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
ICON_NONE);
}
if (ANIM_driver_can_paste()) {