Drivers Setup: Expose all mapping types for creating drivers
authorJoshua Leung <aligorith@gmail.com>
Tue, 29 Mar 2016 14:01:27 +0000 (03:01 +1300)
committerJoshua Leung <aligorith@gmail.com>
Tue, 29 Mar 2016 14:21:57 +0000 (03:21 +1300)
* 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.

source/blender/editors/animation/drivers.c
source/blender/editors/include/ED_keyframing.h
source/blender/editors/interface/interface_eyedropper.c
source/blender/editors/interface/interface_handlers.c

index f94caa4fdd1e52b35923c3abc4b0b066671297e6..eb214e3d1e5c1d5a2eacdaa971d9797da9e4738a 100644 (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 Button Operator ------------------------ */
+/* Add Driver - Enum Defines ------------------------- */
 
-static int add_driver_button_exec(bContext *C, wmOperator *op)
+/* 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;
        
-       const bool all = RNA_boolean_get(op->ptr, "all");
-       int ret = OPERATOR_CANCELLED;
+       int totitem = 0;
+       
+       if (!C) /* needed for docs */
+               return prop_driver_create_mapping_types;
        
-       /* 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 && RNA_property_animateable(&ptr, prop)) {
-               wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true);
-               PointerRNA op_ptr;
+               const bool is_array = RNA_property_array_check(prop);
                
-               WM_operator_properties_create_ptr(&op_ptr, ot);
+               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_poll(bContext *C)
+{
+       PointerRNA ptr = {{NULL}};
+       PropertyRNA *prop = NULL;
+       int index;
+       
+       /* 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;
+       
+       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)) {
+               char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+               short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
                
-               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);
+               if (path) {
+                       success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
+                       MEM_freeN(path);
+               }
+       }
+       
+       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
                
-               ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
+               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);
                
-               WM_operator_properties_free(&op_ptr);
+               /* 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;
        
-       return ret;
+       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 ------------------------ */
index 0c04a45d9d9a309aedb9d69350c4754c7fec02c1..0ad1dc4d8c17dcf4713b95bfc56680e9a93a6ffc 100644 (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 */
index 93d70a556b4100889352e64d65b907f4bc2ec32b..39e41c57c039cb655e0c74602c11cf16730a70be 100644 (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,
index 01fc6aafc4ed933c380f9e52bb39ed70803a5b92..9edc6e58a76a3bc2549b3f72d3e7c05f3cc3267b 100644 (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()) {