From f4fd52796fced406ab9f42f28f4efc29fc702e86 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 16 Oct 2025 11:34:21 +0200 Subject: [PATCH] Fix #148129: Bone Collection select/deselect not working The bone collection operator was not updated to handle the new flag which is now on the `bPoseChannel` instead of the `Bone`. For this to work, the operator now needs the `bArmature` as well as the `Object` and they need to be in sync. Additional code was added to the poll function to ensure this is the case. As a bonus, when working with multiple armatures this now works as expected where only the bones of the active armature are selected even if the armature is shared. The active object is determined by the last bone clicked. Pull Request: https://projects.blender.org/blender/blender/pulls/148185 --- .../editors/armature/bone_collections.cc | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/armature/bone_collections.cc b/source/blender/editors/armature/bone_collections.cc index 9e00d3b91fd..65bab742c82 100644 --- a/source/blender/editors/armature/bone_collections.cc +++ b/source/blender/editors/armature/bone_collections.cc @@ -752,6 +752,17 @@ static bool armature_bone_select_poll(bContext *C) return false; } + const bool is_editmode = armature->edbo != nullptr; + if (!is_editmode) { + Object *active_object = blender::ed::object::context_active_object(C); + if (!active_object || active_object->type != OB_ARMATURE || active_object->data != armature) { + /* There has to be an active object in order to hide a pose bone that points to the correct + * armature. With pinning, the active object may not be an armature. */ + CTX_wm_operator_poll_msg_set(C, "The active object does not match the armature"); + return false; + } + } + if (armature->runtime.active_collection == nullptr) { CTX_wm_operator_poll_msg_set(C, "No active bone collection"); return false; @@ -778,9 +789,17 @@ static void bone_collection_select(bContext *C, } } else { + Object *active_object = blender::ed::object::context_active_object(C); + if (!active_object || active_object->type != OB_ARMATURE || active_object->data != armature) { + /* This is covered by the poll function. */ + BLI_assert_unreachable(); + return; + } LISTBASE_FOREACH (BoneCollectionMember *, member, &bcoll->bones) { Bone *bone = member->bone; - if (!blender::animrig::bone_is_visible(armature, bone)) { + bPoseChannel *pose_bone = BKE_pose_channel_find_name(active_object->pose, bone->name); + BLI_assert_msg(pose_bone != nullptr, "The pose bones and armature bones are out of sync"); + if (!blender::animrig::bone_is_visible(armature, pose_bone)) { continue; } if (bone->flag & BONE_UNSELECTABLE) { @@ -788,12 +807,13 @@ static void bone_collection_select(bContext *C, } if (select) { - bone->flag |= BONE_SELECTED; + pose_bone->flag |= POSE_SELECTED; } else { - bone->flag &= ~BONE_SELECTED; + pose_bone->flag &= ~POSE_SELECTED; } } + DEG_id_tag_update(&active_object->id, ID_RECALC_SELECT); } DEG_id_tag_update(&armature->id, ID_RECALC_SELECT);