diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index f94caa4fdd1..eb214e3d1e5 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -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 ------------------------ */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 0c04a45d9d9..0ad1dc4d8c1 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -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 */ diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 93d70a556b4..39e41c57c03 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -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, diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 01fc6aafc4e..9edc6e58a76 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -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()) {