diff options
-rw-r--r-- | source/blender/blenkernel/BKE_context.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/context.c | 12 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_ops.c | 78 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_access.c | 30 |
5 files changed, 104 insertions, 22 deletions
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 105f8e82343..88a27b67963 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -198,6 +198,9 @@ enum { PointerRNA CTX_data_pointer_get(const bContext *C, const char *member); PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type); +PointerRNA CTX_data_pointer_get_type_silent(const bContext *C, + const char *member, + StructRNA *type); ListBase CTX_data_collection_get(const bContext *C, const char *member); ListBase CTX_data_dir_get_ex(const bContext *C, const bool use_store, diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 2e4f756ce68..e3d95bb660f 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -466,6 +466,18 @@ PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, Stru return PointerRNA_NULL; } +PointerRNA CTX_data_pointer_get_type_silent(const bContext *C, const char *member, StructRNA *type) +{ + PointerRNA ptr = CTX_data_pointer_get(C, member); + + if (ptr.data && RNA_struct_is_a(ptr.type, type)) { + return ptr; + } + else { + return PointerRNA_NULL; + } +} + ListBase CTX_data_collection_get(const bContext *C, const char *member) { bContextDataResult result; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 8af82864b03..2a9ebdfaea9 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -707,6 +707,25 @@ static void UI_OT_override_remove_button(wmOperatorType *ot) /** \name Copy To Selected Operator * \{ */ +#define NOT_NULL(assignment) ((assignment) != NULL) +#define NOT_RNA_NULL(assignment) ((assignment).data != NULL) + +static void ui_context_selected_bones_via_pose(bContext *C, ListBase *r_lb) +{ + ListBase lb; + lb = CTX_data_collection_get(C, "selected_pose_bones"); + + if (!BLI_listbase_is_empty(&lb)) { + CollectionPointerLink *link; + for (link = lb.first; link; link = link->next) { + bPoseChannel *pchan = link->ptr.data; + RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr); + } + } + + *r_lb = lb; +} + bool UI_context_copy_to_selected_list(bContext *C, PointerRNA *ptr, PropertyRNA *prop, @@ -717,6 +736,52 @@ bool UI_context_copy_to_selected_list(bContext *C, *r_use_path_from_id = false; *r_path = NULL; + /* PropertyGroup objects don't have a reference to the struct that actually owns + * them, so it is normally necessary to do a brute force search to find it. This + * handles the search for non-ID owners by using the 'active' reference as a hint + * to preserve efficiency. Only properties defined through RNA are handled, as + * custom properties cannot be assumed to be valid for all instances. + * + * Properties owned by the ID are handled by the 'if (ptr->owner_id)' case below. + */ + if (!RNA_property_is_idprop(prop) && RNA_struct_is_a(ptr->type, &RNA_PropertyGroup)) { + PointerRNA owner_ptr; + char *idpath = NULL; + + /* First, check the active PoseBone and PoseBone->Bone. */ + if (NOT_RNA_NULL( + owner_ptr = CTX_data_pointer_get_type(C, "active_pose_bone", &RNA_PoseBone))) { + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); + } + else { + bPoseChannel *pchan = owner_ptr.data; + RNA_pointer_create(owner_ptr.owner_id, &RNA_Bone, pchan->bone, &owner_ptr); + + if (NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + ui_context_selected_bones_via_pose(C, r_lb); + } + } + } + + if (idpath == NULL) { + /* Check the active EditBone if in edit mode. */ + if (NOT_RNA_NULL( + owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) && + NOT_NULL(idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, ptr->data))) { + *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + } + + /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */ + } + + if (idpath) { + *r_path = BLI_sprintfN("%s.%s", idpath, RNA_property_identifier(prop)); + MEM_freeN(idpath); + return true; + } + } + if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); } @@ -724,18 +789,7 @@ bool UI_context_copy_to_selected_list(bContext *C, *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) { - ListBase lb; - lb = CTX_data_collection_get(C, "selected_pose_bones"); - - if (!BLI_listbase_is_empty(&lb)) { - CollectionPointerLink *link; - for (link = lb.first; link; link = link->next) { - bPoseChannel *pchan = link->ptr.data; - RNA_pointer_create(link->ptr.owner_id, &RNA_Bone, pchan->bone, &link->ptr); - } - } - - *r_lb = lb; + ui_context_selected_bones_via_pose(C, r_lb); } else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 5bf6fb40c6a..7fe88ec94b7 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -40,6 +40,7 @@ struct Main; struct ReportList; struct Scene; struct bContext; +struct IDProperty; /* Types */ extern BlenderRNA BLENDER_RNA; @@ -1156,6 +1157,8 @@ struct PropertyElemRNA { }; bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); +char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, struct IDProperty *needle); + 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); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 78cd99837c3..d8889455ac7 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5738,11 +5738,28 @@ static char *rna_idp_path(PointerRNA *ptr, return path; } +/** + * Find the path from the structure referenced by the pointer to the IDProperty object. + * + * \param ptr Reference to the object owning the custom property storage. + * \param needle Custom property object to find. + * \return Relative path or NULL. + */ +char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle) +{ + IDProperty *haystack = RNA_struct_idprops(ptr, false); + + if (haystack) { /* can fail when called on bones */ + return rna_idp_path(ptr, haystack, needle, NULL); + } + else { + return NULL; + } +} + static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr) { PointerRNA id_ptr; - IDProperty *haystack; - IDProperty *needle; BLI_assert(ptr->owner_id != NULL); @@ -5753,14 +5770,7 @@ static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr) */ RNA_id_pointer_create(ptr->owner_id, &id_ptr); - haystack = RNA_struct_idprops(&id_ptr, false); - if (haystack) { /* can fail when called on bones */ - needle = ptr->data; - return rna_idp_path(&id_ptr, haystack, needle, NULL); - } - else { - return NULL; - } + return RNA_path_from_struct_to_idproperty(&id_ptr, ptr->data); } /** |