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/blender/windowmanager | |
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/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 11 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 95 |
2 files changed, 86 insertions, 20 deletions
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; |