diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-08-31 04:46:47 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-08-31 05:06:47 +0300 |
commit | 3e4d720ae4836783db978b0a378e97b47dcaca87 (patch) | |
tree | cb53100de53f0aa4de38f9e69eb5221b9e8c98fd /source | |
parent | aabe6e3b457f1d4f1b860ed510bf2630a818465e (diff) |
Fix logical error resolving RNA paths
Only append RNA_path_from_ID_to_struct to context attributes if those
paths resolve to ID types.
Also simplify creating RNA paths by adding utility functions:
- WM_context_path_resolve_property_full
- WM_context_path_resolve_full
Part of fix for T90723.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/interface/interface_context_menu.c | 70 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_access.c | 8 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 11 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 95 |
5 files changed, 117 insertions, 71 deletions
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index b953d88c896..e89b8dc7bd7 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -70,26 +70,12 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but) /* If this returns null, we won't be able to bind shortcuts to these RNA properties. * Support can be added at #wm_context_member_from_ptr. */ - const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); - if (member_id == NULL) { + char *final_data_path = WM_context_path_resolve_property_full( + C, &but->rnapoin, but->rnaprop, -1); + if (final_data_path == NULL) { return NULL; } - const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); - const char *member_id_data_path = member_id; - - if (data_path) { - member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path); - MEM_freeN((void *)data_path); - } - - const char *prop_id = RNA_property_identifier(but->rnaprop); - const char *final_data_path = BLI_sprintfN("%s.%s", member_id_data_path, prop_id); - - if (member_id != member_id_data_path) { - MEM_freeN((void *)member_id_data_path); - } - /* Create ID property of data path, to pass to the operator. */ const IDPropertyTemplate val = {0}; IDProperty *prop = IDP_New(IDP_GROUP, &val, __func__); @@ -329,10 +315,24 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) static bool ui_but_is_user_menu_compatible(bContext *C, uiBut *but) { - return (but->optype || - (but->rnaprop && (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) && - (WM_context_member_from_ptr(C, &but->rnapoin) != NULL)) || - UI_but_menutype_get(but)); + bool result = false; + if (but->optype) { + result = true; + } + else if (but->rnaprop) { + if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) { + char *data_path = WM_context_path_resolve_full(C, &but->rnapoin); + if (data_path != NULL) { + MEM_freeN(data_path); + result = true; + } + } + } + else if (UI_but_menutype_get(but)) { + result = true; + } + + return result; } static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *um) @@ -343,21 +343,11 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu * &um->items, but->optype, prop, but->opcontext); } if (but->rnaprop) { - const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); - const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); - const char *member_id_data_path = member_id; - if (data_path) { - member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path); - } + char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin); const char *prop_id = RNA_property_identifier(but->rnaprop); bUserMenuItem *umi = (bUserMenuItem *)ED_screen_user_menu_item_find_prop( &um->items, member_id_data_path, prop_id, but->rnaindex); - if (data_path) { - MEM_freeN((void *)data_path); - } - if (member_id != member_id_data_path) { - MEM_freeN((void *)member_id_data_path); - } + MEM_freeN(member_id_data_path); return umi; } @@ -412,21 +402,11 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um) } else if (but->rnaprop) { /* NOTE: 'member_id' may be a path. */ - const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin); - const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin); - const char *member_id_data_path = member_id; - if (data_path) { - member_id_data_path = BLI_sprintfN("%s.%s", member_id, data_path); - } + char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin); const char *prop_id = RNA_property_identifier(but->rnaprop); /* NOTE: ignore 'drawstr', use property idname always. */ ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex); - if (data_path) { - MEM_freeN((void *)data_path); - } - if (member_id != member_id_data_path) { - MEM_freeN((void *)member_id_data_path); - } + MEM_freeN(member_id_data_path); } else if ((mt = UI_but_menutype_get(but))) { ED_screen_user_menu_item_add_menu(&um->items, drawstr, mt); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index abbe609d0ef..76155973982 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -1162,7 +1162,7 @@ char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *nee struct ID *RNA_find_real_ID_and_path(struct Main *bmain, struct ID *id, const char **r_path); -char *RNA_path_from_ID_to_struct(PointerRNA *ptr); +char *RNA_path_from_ID_to_struct(const PointerRNA *ptr); char *RNA_path_from_real_ID_to_struct(struct Main *bmain, PointerRNA *ptr, struct ID **r_real); @@ -1192,7 +1192,7 @@ char *RNA_path_full_property_py(struct Main *bmain, struct PropertyRNA *prop, int index); char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); -char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); +char *RNA_path_property_py(const struct PointerRNA *ptr, struct PropertyRNA *prop, int index); /* Quick name based property access * diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index a2905018cc7..51e20eb9e7f 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5690,7 +5690,7 @@ char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle) return NULL; } -static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr) +static char *rna_path_from_ID_to_idpgroup(const PointerRNA *ptr) { PointerRNA id_ptr; @@ -5775,7 +5775,7 @@ static char *rna_prepend_real_ID_path(Main *bmain, ID *id, char *path, ID **r_re return prefix[0] != '\0' ? BLI_strdup(prefix) : NULL; } -char *RNA_path_from_ID_to_struct(PointerRNA *ptr) +char *RNA_path_from_ID_to_struct(const PointerRNA *ptr) { char *ptrpath = NULL; @@ -5786,7 +5786,7 @@ char *RNA_path_from_ID_to_struct(PointerRNA *ptr) if (!RNA_struct_is_ID(ptr->type)) { if (ptr->type->path) { /* if type has a path to some ID, use it */ - ptrpath = ptr->type->path(ptr); + ptrpath = ptr->type->path((PointerRNA *)ptr); } else if (ptr->type->nested && RNA_struct_is_ID(ptr->type->nested)) { PointerRNA parentptr; @@ -6156,7 +6156,7 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) * Get the struct.property as a python representation, eg: * some_prop[10] */ -char *RNA_path_property_py(PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index) +char *RNA_path_property_py(const PointerRNA *UNUSED(ptr), PropertyRNA *prop, int index) { char *ret; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ca1610a8101..7ecbcad886d 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -262,8 +262,9 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *han wmKeyMap *keymap, int priority); -typedef struct wmKeyMap *(wmEventHandler_KeymapDynamicFn)( - wmWindowManager *wm, struct wmEventHandler_Keymap *handler)ATTR_WARN_UNUSED_RESULT; +typedef struct wmKeyMap *(wmEventHandler_KeymapDynamicFn)(wmWindowManager *wm, + struct wmEventHandler_Keymap *handler) + ATTR_WARN_UNUSED_RESULT; struct wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback( struct wmWindowManager *wm, struct wmEventHandler_Keymap *handler); @@ -573,7 +574,11 @@ void WM_operator_py_idname(char *to, const char *from); bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname); -const char *WM_context_member_from_ptr(struct bContext *C, const struct PointerRNA *ptr); +char *WM_context_path_resolve_property_full(struct bContext *C, + const PointerRNA *ptr, + PropertyRNA *prop, + int index); +char *WM_context_path_resolve_full(struct bContext *C, const PointerRNA *ptr); /* wm_operator_type.c */ struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index f1a8f4ffd71..dab3d7525db 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -55,6 +55,7 @@ #include "BLI_dial_2d.h" #include "BLI_dynstr.h" /* For #WM_operator_pystring. */ #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_brush.h" @@ -347,7 +348,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max) /* return NULL if no match is found */ #if 0 -static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr) +static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr, bool *r_is_id) { /* loop over all context items and do 2 checks * @@ -362,6 +363,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr const char *member_found = NULL; const char *member_id = NULL; + bool member_found_is_id = false; for (link = lb.first; link; link = link->next) { const char *identifier = link->data; @@ -373,14 +375,15 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr } if (ptr->owner_id == ctx_item_ptr.owner_id) { + const bool is_id = RNA_struct_is_ID(ctx_item_ptr.type); if ((ptr->data == ctx_item_ptr.data) && (ptr->type == ctx_item_ptr.type)) { /* found! */ member_found = identifier; + member_found_is_id = is_id; break; } - else if (RNA_struct_is_ID(ctx_item_ptr.type)) { - /* we found a reference to this ID, - * so fallback to it if there is no direct reference */ + if (is_id) { + /* Found a reference to this ID, so fallback to it if there is no direct reference. */ member_id = identifier; } } @@ -388,9 +391,11 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr BLI_freelistN(&lb); if (member_found) { + *r_is_id = member_found_is_id; return member_found; } else if (member_id) { + *r_is_id = true; return member_id; } else { @@ -402,9 +407,24 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr /* use hard coded checks for now */ -static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr) +/** + * \param: r_is_id: + * - When set to true, the returned member is an ID type. + * This is a signal that #RNA_path_from_ID_to_struct needs to be used to calculate + * the remainder of the RNA path. + * - When set to false, the returned member is not an ID type. + * In this case the context path *must* resolve to `ptr`, + * since there is no convenient way to calculate partial RNA paths. + * + * \note While the path to the ID is typically sufficient to calculate the remainder of the path, + * in practice this would cause #WM_context_path_resolve_property_full to crate a path such as: + * `object.data.bones["Bones"].use_deform` such paths are not useful for key-shortcuts, + * so this function supports returning data-paths directly to context members that aren't ID types. + */ +static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr, bool *r_is_id) { const char *member_id = NULL; + bool is_id = false; if (ptr->owner_id) { @@ -414,6 +434,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \ if (ctx_item_ptr.owner_id == idptr) { \ member_id = ctx_member; \ + is_id = true; \ break; \ } \ } \ @@ -426,6 +447,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, ctx_member); \ if (ctx_item_ptr.owner_id && (ID *)cast(ctx_item_ptr.owner_id) == idptr) { \ member_id = ctx_member_full; \ + is_id = true; \ break; \ } \ } \ @@ -530,32 +552,71 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr # undef TEST_PTR_DATA_TYPE } + *r_is_id = is_id; + return member_id; } #endif +/** + * Calculate the path to `ptr` from constex `C`, or return NULL if it can't be calculated. + */ +char *WM_context_path_resolve_property_full(bContext *C, + const PointerRNA *ptr, + PropertyRNA *prop, + int index) +{ + bool is_id; + const char *member_id = wm_context_member_from_ptr(C, ptr, &is_id); + char *member_id_data_path = NULL; + if (member_id != NULL) { + if (is_id && !RNA_struct_is_ID(ptr->type)) { + char *data_path = RNA_path_from_ID_to_struct(ptr); + if (data_path != NULL) { + if (prop != NULL) { + char *prop_str = RNA_path_property_py(ptr, prop, index); + member_id_data_path = BLI_string_join_by_sep_charN('.', member_id, data_path, prop_str); + MEM_freeN(prop_str); + } + else { + member_id_data_path = BLI_string_join_by_sep_charN('.', member_id, data_path); + } + MEM_freeN(data_path); + } + } + else { + if (prop != NULL) { + char *prop_str = RNA_path_property_py(ptr, prop, index); + member_id_data_path = BLI_string_join_by_sep_charN('.', member_id, prop_str); + MEM_freeN(prop_str); + } + else { + member_id_data_path = BLI_strdup(member_id); + } + } + } + return member_id_data_path; +} + +char *WM_context_path_resolve_full(bContext *C, const PointerRNA *ptr) +{ + return WM_context_path_resolve_property_full(C, ptr, NULL, -1); +} + static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index) { - const char *member_id = wm_context_member_from_ptr(C, ptr); + char *member_id_data_path = WM_context_path_resolve_property_full(C, ptr, prop, index); char *ret = NULL; - if (member_id != NULL) { - char *prop_str = RNA_path_struct_property_py(ptr, prop, index); - if (prop_str) { - ret = BLI_sprintfN("bpy.context.%s.%s", member_id, prop_str); - MEM_freeN(prop_str); - } + if (member_id_data_path != NULL) { + ret = BLI_sprintfN("bpy.context.%s", member_id_data_path); + MEM_freeN(member_id_data_path); } return ret; } -const char *WM_context_member_from_ptr(bContext *C, const PointerRNA *ptr) -{ - return wm_context_member_from_ptr(C, ptr); -} - char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index) { char *lhs = C ? wm_prop_pystring_from_context(C, ptr, prop, index) : NULL; |