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.
This commit is contained in:
parent
aabe6e3b45
commit
3e4d720ae4
Notes:
blender-bot
2023-02-14 05:37:19 +01:00
Referenced by commit 8d40d61af0
, Fix T91225: Quick Favorites and shortcuts are broken for some properties
Referenced by issue #91225, Quick Favorites and shortcuts are broken for many properties.
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue