diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index a0c341ad06b..469e99dced8 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -1038,15 +1038,31 @@ static void override_idtemplate_menu() #define NOT_RNA_NULL(assignment) ((assignment).data != nullptr) +/** + * Construct a PointerRNA that points to pchan->bone. + * + * Pose bones are owned by an Object, whereas `pchan->bone` is owned by the Armature, so this + * doesn't just remap the pointer's `data` field, but also its `owner_id`. + */ +static PointerRNA rnapointer_pchan_to_bone(const PointerRNA &pchan_ptr) +{ + bPoseChannel *pchan = static_cast(pchan_ptr.data); + + BLI_assert(GS(pchan_ptr.owner_id->name) == ID_OB); + Object *object = reinterpret_cast(pchan_ptr.owner_id); + + BLI_assert(GS(static_cast(object->data)->name) == ID_AR); + bArmature *armature = static_cast(object->data); + + return RNA_pointer_create_discrete(&armature->id, &RNA_Bone, pchan->bone); +} + static void ui_context_selected_bones_via_pose(bContext *C, blender::Vector *r_lb) { blender::Vector lb = CTX_data_collection_get(C, "selected_pose_bones"); - if (!lb.is_empty()) { - for (PointerRNA &ptr : lb) { - bPoseChannel *pchan = static_cast(ptr.data); - ptr = RNA_pointer_create_discrete(ptr.owner_id, &RNA_Bone, pchan->bone); - } + for (PointerRNA &ptr : lb) { + ptr = rnapointer_pchan_to_bone(ptr); } *r_lb = std::move(lb); @@ -1109,9 +1125,8 @@ bool UI_context_copy_to_selected_list(bContext *C, *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else { - bPoseChannel *pchan = static_cast(owner_ptr.data); - owner_ptr = RNA_pointer_create_discrete(owner_ptr.owner_id, &RNA_Bone, pchan->bone); - idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, + PointerRNA bone_ptr = rnapointer_pchan_to_bone(owner_ptr); + idpath = RNA_path_from_struct_to_idproperty(&bone_ptr, static_cast(ptr->data)); if (idpath) { ui_context_selected_bones_via_pose(C, r_lb); @@ -1121,13 +1136,14 @@ bool UI_context_copy_to_selected_list(bContext *C, if (!idpath) { /* Check the active EditBone if in edit mode. */ - idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, - static_cast(ptr->data)); if (NOT_RNA_NULL( - owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone)) && - idpath) + owner_ptr = CTX_data_pointer_get_type_silent(C, "active_bone", &RNA_EditBone))) { - *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + idpath = RNA_path_from_struct_to_idproperty(&owner_ptr, + static_cast(ptr->data)); + if (idpath) { + *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + } } /* Add other simple cases here (Node, NodeSocket, Sequence, ViewLayer etc). */ @@ -1146,6 +1162,9 @@ 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)) { + /* "selected_bones" or "selected_editable_bones" will only yield anything in Armature Edit + * mode. In other modes, it'll be empty, and the only way to get the selected bones is via + * "selected_pose_bones". */ ui_context_selected_bones_via_pose(C, r_lb); } else if (RNA_struct_is_a(ptr->type, &RNA_BoneColor)) {