UI: support enum key shortcut detection
authorCampbell Barton <ideasman42@gmail.com>
Thu, 29 Nov 2018 06:32:35 +0000 (17:32 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 29 Nov 2018 06:32:35 +0000 (17:32 +1100)
Shows shortcuts in space-selector.

source/blender/editors/interface/interface.c

index 6fc627d384795b16486f7638f2345444352ff79d..aeee93b055bdf9befa31cd8e9729780c5bad068f 100644 (file)
@@ -90,6 +90,7 @@
 
 /* prototypes. */
 static void ui_but_to_pixelrect(struct rcti *rect, const struct ARegion *ar, struct uiBlock *block, struct uiBut *but);
+static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *but_p);
 
 /* avoid unneeded calls to ui_but_value_get */
 #define UI_BUT_VALUE_UNSET DBL_MAX
@@ -1067,12 +1068,35 @@ static bool ui_but_event_property_operator_string(
                "WM_OT_context_menu_enum",
                NULL
        };
-       const size_t num_ops = sizeof(ctx_toggle_opnames) / sizeof(const char *);
+
+       const char *ctx_enum_opnames[] = {
+               "WM_OT_context_set_enum",
+               NULL
+       };
+
+       int  prop_enum_value = -1;
+       bool prop_enum_value_ok = false;
+       PointerRNA *ptr = &but->rnapoin;
+       PropertyRNA *prop = but->rnaprop;
+       if ((but->type == UI_BTYPE_BUT_MENU) && (but->block->handle != NULL)) {
+               uiBut *but_parent = but->block->handle->popup_create_vars.but;
+               if ((but->type == UI_BTYPE_BUT_MENU) &&
+                   but_parent && (but_parent->menu_create_func == ui_def_but_rna__menu))
+               {
+                       prop_enum_value = (int)but->hardmin;
+                       ptr = &but->block->handle->popup_create_vars.but->rnapoin;
+                       prop = but->block->handle->popup_create_vars.but->rnaprop;
+                       prop_enum_value_ok = true;
+               }
+       }
 
        bool found = false;
 
+       /* Don't use the button again. */
+       but = NULL;
+
        /* this version is only for finding hotkeys for properties (which get set via context using operators) */
-       if (but->rnaprop) {
+       if (prop) {
                /* to avoid massive slowdowns on property panels, for now, we only check the
                 * hotkeys for Editor / Scene settings...
                 *
@@ -1081,40 +1105,51 @@ static bool ui_but_event_property_operator_string(
                // TODO: value (for enum stuff)?
                char *data_path = NULL;
 
-               if (but->rnapoin.id.data) {
-                       ID *id = but->rnapoin.id.data;
+               if (ptr->id.data) {
+                       ID *id = ptr->id.data;
 
                        if (GS(id->name) == ID_SCR) {
                                /* screen/editor property
                                 * NOTE: in most cases, there is actually no info for backwards tracing
                                 * how to get back to ID from the editor data we may be dealing with
                                 */
-                               if (RNA_struct_is_a(but->rnapoin.type, &RNA_Space)) {
+                               if (RNA_struct_is_a(ptr->type, &RNA_Space)) {
+                                       /* data should be directly on here... */
+                                       data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(prop));
+                               }
+                               else if (RNA_struct_is_a(ptr->type, &RNA_Area)) {
                                        /* data should be directly on here... */
-                                       data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(but->rnaprop));
+                                       const char *prop_id = RNA_property_identifier(prop);
+                                       /* Hack since keys access 'type'. */
+                                       if (STREQ(prop_id, "ui_type")) {
+                                               prop_id = "type";
+                                               prop_enum_value >>= 16;
+                                               prop = RNA_struct_find_property(ptr, prop_id);
+                                       }
+                                       data_path = BLI_sprintfN("area.%s", prop_id);
                                }
                                else {
                                        /* special exceptions for common nested data in editors... */
-                                       if (RNA_struct_is_a(but->rnapoin.type, &RNA_DopeSheet)) {
+                                       if (RNA_struct_is_a(ptr->type, &RNA_DopeSheet)) {
                                                /* dopesheet filtering options... */
-                                               data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop));
+                                               data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(prop));
                                        }
-                                       else if (RNA_struct_is_a(but->rnapoin.type, &RNA_FileSelectParams)) {
+                                       else if (RNA_struct_is_a(ptr->type, &RNA_FileSelectParams)) {
                                                /* Filebrowser options... */
-                                               data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(but->rnaprop));
+                                               data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(prop));
                                        }
                                }
                        }
                        else if (GS(id->name) == ID_SCE) {
-                               if (RNA_struct_is_a(but->rnapoin.type, &RNA_ToolSettings)) {
+                               if (RNA_struct_is_a(ptr->type, &RNA_ToolSettings)) {
                                        /* toolsettings property
                                         * NOTE: toolsettings is usually accessed directly (i.e. not through scene)
                                         */
-                                       data_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+                                       data_path = RNA_path_from_ID_to_property(ptr, prop);
                                }
                                else {
                                        /* scene property */
-                                       char *path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+                                       char *path = RNA_path_from_ID_to_property(ptr, prop);
 
                                        if (path) {
                                                data_path = BLI_sprintfN("scene.%s", path);
@@ -1123,7 +1158,7 @@ static bool ui_but_event_property_operator_string(
 #if 0
                                        else {
                                                printf("ERROR in %s(): Couldn't get path for scene property - %s\n",
-                                                      __func__, RNA_property_identifier(but->rnaprop));
+                                                      __func__, RNA_property_identifier(prop));
                                        }
 #endif
                                }
@@ -1132,26 +1167,50 @@ static bool ui_but_event_property_operator_string(
                                //puts("other id");
                        }
 
-                       //printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(but->rnaprop), data_path);
+                       //printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(prop), data_path);
                }
 
                /* we have a datapath! */
                if (data_path) {
-                       size_t i;
-
                        /* create a property to host the "datapath" property we're sending to the operators */
                        IDProperty *prop_path;
-                       IDProperty *prop_path_value;
 
                        IDPropertyTemplate val = {0};
                        prop_path = IDP_New(IDP_GROUP, &val, __func__);
-                       prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1);
-                       IDP_AddToGroup(prop_path, prop_path_value);
+                       IDP_AddToGroup(prop_path, IDP_NewString(data_path, "data_path", strlen(data_path) + 1));
+
+                       const char **opnames;
+                       int          opnames_len;
+
+                       if (prop_enum_value_ok && prop && RNA_property_type(prop) == PROP_ENUM) {
+                               opnames_len = ARRAY_SIZE(ctx_enum_opnames) - 1;
+                               opnames                = ctx_enum_opnames;
+
+                               const EnumPropertyItem *item;
+                               bool free;
+                               RNA_property_enum_items((bContext *)C, ptr, prop, &item, NULL, &free);
+                               int index = RNA_enum_from_value(item, prop_enum_value);
+                               if (index != -1) {
+                                       const char *id = item[index].identifier;
+                                       IDP_AddToGroup(prop_path, IDP_NewString(id, "value", strlen(id) + 1));
+                               }
+                               else {
+                                       opnames_len = 0;  /* Do nothing. */
+                               }
+                               if (free) {
+                                       MEM_freeN((void *)item);
+                               }
+                       }
+                       else {
+                               opnames_len = ARRAY_SIZE(ctx_toggle_opnames) - 1;
+                               opnames                = ctx_toggle_opnames;
+                       }
 
                        /* check each until one works... */
-                       for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) {
+
+                       for (int i = 0; (i < opnames_len) && (opnames[i]); i++) {
                                if (WM_key_event_operator_string(
-                                           C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
+                                           C, opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
                                            buf, buf_len))
                                {
                                        found = true;