2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, 2002-2009 full recode.
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/armature/pose_select.c
32 #include "DNA_anim_types.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_constraint_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
38 #include "MEM_guardedalloc.h"
40 #include "BLI_blenlib.h"
42 #include "BKE_action.h"
43 #include "BKE_armature.h"
44 #include "BKE_constraint.h"
45 #include "BKE_context.h"
46 #include "BKE_object.h"
47 #include "BKE_report.h"
49 #include "DEG_depsgraph.h"
51 #include "RNA_access.h"
52 #include "RNA_define.h"
57 #include "ED_armature.h"
58 #include "ED_keyframing.h"
60 #include "ED_object.h"
61 #include "ED_screen.h"
62 #include "ED_view3d.h"
64 #include "armature_intern.h"
66 /* utility macros for storing a temp int in the bone (selection flag) */
67 #define PBONE_PREV_FLAG_GET(pchan) ((void)0, (GET_INT_FROM_POINTER((pchan)->temp)))
68 #define PBONE_PREV_FLAG_SET(pchan, val) ((pchan)->temp = SET_INT_IN_POINTER(val))
71 /* ***************** Pose Select Utilities ********************* */
73 /* Note: SEL_TOGGLE is assumed to have already been handled! */
74 static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
76 /* select pchan only if selectable, but deselect works always */
77 switch (select_mode) {
79 if (!(pchan->bone->flag & BONE_UNSELECTABLE))
80 pchan->bone->flag |= BONE_SELECTED;
83 pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
86 if (pchan->bone->flag & BONE_SELECTED) {
87 pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
89 else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
90 pchan->bone->flag |= BONE_SELECTED;
96 /* Utility method for changing the selection status of a bone */
97 void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
102 // XXX: actually, we can probably still get away with no object - at most we have no updates
103 if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone))
108 /* can only change selection state if bone can be modified */
109 if (PBONE_SELECTABLE(arm, pchan->bone)) {
110 /* change selection state - activate too if selected */
112 pchan->bone->flag |= BONE_SELECTED;
113 arm->act_bone = pchan->bone;
116 pchan->bone->flag &= ~BONE_SELECTED;
117 arm->act_bone = NULL;
120 // TODO: select and activate corresponding vgroup?
122 /* tag necessary depsgraph updates
123 * (see rna_Bone_select_update() in rna_armature.c for details)
125 if (arm->flag & ARM_HAS_VIZ_DEPS) {
126 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
129 /* send necessary notifiers */
130 WM_main_add_notifier(NC_GEOM | ND_DATA, ob);
134 /* called from editview.c, for mode-less pose selection */
135 /* assumes scene obact and basact is still on old situation */
136 bool ED_do_pose_selectbuffer(
137 Scene *scene, SceneLayer *sl, Base *base, const unsigned int *buffer, short hits,
138 bool extend, bool deselect, bool toggle, bool do_nearest)
140 Object *ob = base->object;
143 if (!ob || !ob->pose) return 0;
145 nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest);
147 /* if the bone cannot be affected, don't do anything */
148 if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
149 Object *ob_act = OBACT_NEW;
150 bArmature *arm = ob->data;
152 /* since we do unified select, we don't shift+select a bone if the
153 * armature object was not active yet.
154 * note, special exception for armature mode so we can do multi-select
155 * we could check for multi-select explicitly but think its fine to
156 * always give predictable behavior in weight paint mode - campbell */
157 if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)) {
158 /* when we are entering into posemode via toggle-select,
159 * frop another active object - always select the bone. */
160 if (!extend && !deselect && toggle) {
161 /* re-select below */
162 nearBone->flag &= ~BONE_SELECTED;
166 if (!extend && !deselect && !toggle) {
167 ED_pose_de_selectall(ob, SEL_DESELECT, true);
168 nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
169 arm->act_bone = nearBone;
173 nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
174 arm->act_bone = nearBone;
177 nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
180 if (nearBone->flag & BONE_SELECTED) {
181 /* if not active, we make it active */
182 if (nearBone != arm->act_bone) {
183 arm->act_bone = nearBone;
186 nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
190 nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
191 arm->act_bone = nearBone;
197 /* in weightpaint we select the associated vertex group too */
198 if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
199 if (nearBone == arm->act_bone) {
200 ED_vgroup_select_by_name(ob_act, nearBone->name);
201 DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
204 /* if there are some dependencies for visualizing armature state
205 * (e.g. Mask Modifier in 'Armature' mode), force update
207 else if (arm->flag & ARM_HAS_VIZ_DEPS) {
208 /* NOTE: ob not ob_act here is intentional - it's the source of the
209 * bones being selected [T37247]
211 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
216 return nearBone != NULL;
219 /* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
220 * When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
221 void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility)
223 bArmature *arm = ob->data;
226 /* we call this from outliner too */
227 if (ob->pose == NULL) {
231 /* Determine if we're selecting or deselecting */
232 if (select_mode == SEL_TOGGLE) {
233 select_mode = SEL_SELECT;
234 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
235 if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
236 if (pchan->bone->flag & BONE_SELECTED) {
237 select_mode = SEL_DESELECT;
244 /* Set the flags accordingly */
245 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
246 /* ignore the pchan if it isn't visible or if its selection cannot be changed */
247 if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
248 pose_do_bone_select(pchan, select_mode);
253 /* ***************** Selections ********************** */
255 static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
259 /* stop when unconnected child is encountered, or when unselectable bone is encountered */
260 if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
263 /* XXX old cruft! use notifiers instead */
264 //select_actionchannel_by_name (ob->action, bone->name, !(shift));
267 bone->flag &= ~BONE_SELECTED;
269 bone->flag |= BONE_SELECTED;
271 for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
272 selectconnected_posebonechildren(ob, curBone, extend);
275 /* within active object context */
276 /* previously known as "selectconnected_posearmature" */
277 static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
279 Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
280 bArmature *arm = (bArmature *)ob->data;
281 Bone *bone, *curBone, *next = NULL;
282 const bool extend = RNA_boolean_get(op->ptr, "extend");
284 view3d_operator_needs_opengl(C);
286 bone = get_nearest_bone(C, event->mval, !extend);
289 return OPERATOR_CANCELLED;
292 for (curBone = bone; curBone; curBone = next) {
293 /* ignore bone if cannot be selected */
294 if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
296 curBone->flag &= ~BONE_SELECTED;
298 curBone->flag |= BONE_SELECTED;
300 if (curBone->flag & BONE_CONNECTED)
301 next = curBone->parent;
309 /* Select children */
310 for (curBone = bone->childbase.first; curBone; curBone = next)
311 selectconnected_posebonechildren(ob, curBone, extend);
314 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
316 if (arm->flag & ARM_HAS_VIZ_DEPS) {
317 /* mask modifier ('armature' mode), etc. */
318 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
321 return OPERATOR_FINISHED;
324 static int pose_select_linked_poll(bContext *C)
326 return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
329 void POSE_OT_select_linked(wmOperatorType *ot)
332 ot->name = "Select Connected";
333 ot->idname = "POSE_OT_select_linked";
334 ot->description = "Select bones related to selected ones by parent/child relationships";
337 /* leave 'exec' unset */
338 ot->invoke = pose_select_connected_invoke;
339 ot->poll = pose_select_linked_poll;
342 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
345 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
348 /* -------------------------------------- */
350 static int pose_de_select_all_exec(bContext *C, wmOperator *op)
352 int action = RNA_enum_get(op->ptr, "action");
354 Scene *scene = CTX_data_scene(C);
355 Object *ob = ED_object_context(C);
356 bArmature *arm = ob->data;
357 int multipaint = scene->toolsettings->multipaint;
359 if (action == SEL_TOGGLE) {
360 action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
364 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
366 pose_do_bone_select(pchan, action);
370 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
372 /* weightpaint or mask modifiers need depsgraph updates */
373 if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
374 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
377 return OPERATOR_FINISHED;
380 void POSE_OT_select_all(wmOperatorType *ot)
383 ot->name = "(De)select All";
384 ot->idname = "POSE_OT_select_all";
385 ot->description = "Toggle selection status of all bones";
388 ot->exec = pose_de_select_all_exec;
389 ot->poll = ED_operator_posemode;
392 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
394 WM_operator_properties_select_all(ot);
397 /* -------------------------------------- */
399 static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
401 Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
402 bArmature *arm = (bArmature *)ob->data;
403 bPoseChannel *pchan, *parent;
405 /* Determine if there is an active bone */
406 pchan = CTX_data_active_pose_bone(C);
408 parent = pchan->parent;
409 if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
410 parent->bone->flag |= BONE_SELECTED;
411 arm->act_bone = parent->bone;
414 return OPERATOR_CANCELLED;
418 return OPERATOR_CANCELLED;
422 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
424 if (arm->flag & ARM_HAS_VIZ_DEPS) {
425 /* mask modifier ('armature' mode), etc. */
426 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
429 return OPERATOR_FINISHED;
432 void POSE_OT_select_parent(wmOperatorType *ot)
435 ot->name = "Select Parent Bone";
436 ot->idname = "POSE_OT_select_parent";
437 ot->description = "Select bones that are parents of the currently selected bones";
440 ot->exec = pose_select_parent_exec;
441 ot->poll = ED_operator_posemode;
444 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
447 /* -------------------------------------- */
449 static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
451 Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
452 bArmature *arm = (bArmature *)ob->data;
456 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
458 if (pchan->bone->flag & BONE_SELECTED) {
459 for (con = pchan->constraints.first; con; con = con->next) {
460 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
461 ListBase targets = {NULL, NULL};
462 bConstraintTarget *ct;
464 if (cti && cti->get_constraint_targets) {
465 cti->get_constraint_targets(con, &targets);
467 for (ct = targets.first; ct; ct = ct->next) {
468 if ((ct->tar == ob) && (ct->subtarget[0])) {
469 bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
470 if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
471 pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
477 if (cti->flush_constraint_targets)
478 cti->flush_constraint_targets(con, &targets, 1);
486 return OPERATOR_CANCELLED;
489 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
491 if (arm->flag & ARM_HAS_VIZ_DEPS) {
492 /* mask modifier ('armature' mode), etc. */
493 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
496 return OPERATOR_FINISHED;
499 void POSE_OT_select_constraint_target(wmOperatorType *ot)
502 ot->name = "Select Constraint Target";
503 ot->idname = "POSE_OT_select_constraint_target";
504 ot->description = "Select bones used as targets for the currently selected bones";
507 ot->exec = pose_select_constraint_target_exec;
508 ot->poll = ED_operator_posemode;
511 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
514 /* -------------------------------------- */
516 static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
518 Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
519 bArmature *arm = ob->data;
520 bPoseChannel *pchan_act;
521 int direction = RNA_enum_get(op->ptr, "direction");
522 const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
523 bool changed = false;
525 pchan_act = BKE_pose_channel_active(ob);
526 if (pchan_act == NULL) {
527 return OPERATOR_CANCELLED;
530 if (direction == BONE_SELECT_PARENT) {
531 if (pchan_act->parent) {
533 bone_parent = pchan_act->parent->bone;
535 if (PBONE_SELECTABLE(arm, bone_parent)) {
537 pchan_act->bone->flag &= ~BONE_SELECTED;
539 bone_parent->flag |= BONE_SELECTED;
540 arm->act_bone = bone_parent;
546 else { /* direction == BONE_SELECT_CHILD */
547 bPoseChannel *pchan_iter;
548 Bone *bone_child = NULL;
551 /* first pass, only connected bones (the logical direct child) */
552 for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
553 for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
554 /* possible we have multiple children, some invisible */
555 if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
556 if (pchan_iter->parent == pchan_act) {
557 if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
558 bone_child = pchan_iter->bone;
567 arm->act_bone = bone_child;
570 pchan_act->bone->flag &= ~BONE_SELECTED;
572 bone_child->flag |= BONE_SELECTED;
578 if (changed == false) {
579 return OPERATOR_CANCELLED;
583 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
585 if (arm->flag & ARM_HAS_VIZ_DEPS) {
586 /* mask modifier ('armature' mode), etc. */
587 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
590 return OPERATOR_FINISHED;
593 void POSE_OT_select_hierarchy(wmOperatorType *ot)
595 static EnumPropertyItem direction_items[] = {
596 {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
597 {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
598 {0, NULL, 0, NULL, NULL}
602 ot->name = "Select Hierarchy";
603 ot->idname = "POSE_OT_select_hierarchy";
604 ot->description = "Select immediate parent/children of selected bones";
607 ot->exec = pose_select_hierarchy_exec;
608 ot->poll = ED_operator_posemode;
611 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
614 ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
615 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
618 /* -------------------------------------- */
620 /* modes for select same */
621 typedef enum ePose_SelectSame_Mode {
622 POSE_SEL_SAME_LAYER = 0,
623 POSE_SEL_SAME_GROUP = 1,
624 POSE_SEL_SAME_KEYINGSET = 2,
625 } ePose_SelectSame_Mode;
627 static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
629 bArmature *arm = (ob) ? ob->data : NULL;
630 bPose *pose = (ob) ? ob->pose : NULL;
633 bool changed = false, tagged = false;
636 if (ELEM(NULL, ob, pose, arm))
639 /* count the number of groups */
640 numGroups = BLI_listbase_count(&pose->agroups);
644 /* alloc a small array to keep track of the groups to use
645 * - each cell stores on/off state for whether group should be used
646 * - size is (numGroups + 1), since (index = 0) is used for no-group
648 group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
650 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
652 /* keep track of group as group to use later? */
653 if (pchan->bone->flag & BONE_SELECTED) {
654 group_flags[pchan->agrp_index] = 1;
658 /* deselect all bones before selecting new ones? */
659 if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
660 pchan->bone->flag &= ~BONE_SELECTED;
664 /* small optimization: only loop through bones a second time if there are any groups tagged */
666 /* only if group matches (and is not selected or current bone) */
667 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
669 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
670 /* check if the group used by this bone is counted */
671 if (group_flags[pchan->agrp_index]) {
672 pchan->bone->flag |= BONE_SELECTED;
681 MEM_freeN(group_flags);
686 static bool pose_select_same_layer(bContext *C, Object *ob, bool extend)
688 bPose *pose = (ob) ? ob->pose : NULL;
689 bArmature *arm = (ob) ? ob->data : NULL;
690 bool changed = false;
693 if (ELEM(NULL, ob, pose, arm))
696 /* figure out what bones are selected */
697 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
699 /* keep track of layers to use later? */
700 if (pchan->bone->flag & BONE_SELECTED)
701 layers |= pchan->bone->layer;
703 /* deselect all bones before selecting new ones? */
704 if ((extend == false) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
705 pchan->bone->flag &= ~BONE_SELECTED;
711 /* select bones that are on same layers as layers flag */
712 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
714 /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
715 if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
716 pchan->bone->flag |= BONE_SELECTED;
725 static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object *ob, bool extend)
727 KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
730 bArmature *arm = (ob) ? ob->data : NULL;
731 bPose *pose = (ob) ? ob->pose : NULL;
732 bool changed = false;
734 /* sanity checks: validate Keying Set and object */
736 BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
739 else if (ANIM_validate_keyingset(C, NULL, ks) != 0) {
740 if (ks->paths.first == NULL) {
741 if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
742 BKE_report(reports, RPT_ERROR,
743 "Use another Keying Set, as the active one depends on the currently "
744 "selected items or cannot find any targets due to unsuitable context");
747 BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
753 if (ELEM(NULL, ob, pose, arm))
756 /* if not extending selection, deselect all selected first */
757 if (extend == false) {
758 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
760 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
761 pchan->bone->flag &= ~BONE_SELECTED;
766 /* iterate over elements in the Keying Set, setting selection depending on whether
767 * that bone is visible or not...
769 for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
770 /* only items related to this object will be relevant */
771 if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
772 if (strstr(ksp->rna_path, "bones")) {
773 char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
776 bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
779 /* select if bone is visible and can be affected */
780 if (PBONE_SELECTABLE(arm, pchan->bone)) {
781 pchan->bone->flag |= BONE_SELECTED;
786 /* free temp memory */
796 static int pose_select_grouped_exec(bContext *C, wmOperator *op)
798 Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
799 bArmature *arm = (bArmature *)ob->data;
800 const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
801 const bool extend = RNA_boolean_get(op->ptr, "extend");
802 bool changed = false;
805 if (ob->pose == NULL)
806 return OPERATOR_CANCELLED;
808 /* selection types */
810 case POSE_SEL_SAME_LAYER: /* layer */
811 changed = pose_select_same_layer(C, ob, extend);
814 case POSE_SEL_SAME_GROUP: /* group */
815 changed = pose_select_same_group(C, ob, extend);
818 case POSE_SEL_SAME_KEYINGSET: /* Keying Set */
819 changed = pose_select_same_keyingset(C, op->reports, ob, extend);
823 printf("pose_select_grouped() - Unknown selection type %u\n", type);
827 /* notifiers for updates */
828 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
830 if (arm->flag & ARM_HAS_VIZ_DEPS) {
831 /* mask modifier ('armature' mode), etc. */
832 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
835 /* report done status */
837 return OPERATOR_FINISHED;
839 return OPERATOR_CANCELLED;
842 void POSE_OT_select_grouped(wmOperatorType *ot)
844 static EnumPropertyItem prop_select_grouped_types[] = {
845 {POSE_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
846 {POSE_SEL_SAME_GROUP, "GROUP", 0, "Group", "Shared group"},
847 {POSE_SEL_SAME_KEYINGSET, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
848 {0, NULL, 0, NULL, NULL}
852 ot->name = "Select Grouped";
853 ot->description = "Select all visible bones grouped by similar properties";
854 ot->idname = "POSE_OT_select_grouped";
857 ot->invoke = WM_menu_invoke;
858 ot->exec = pose_select_grouped_exec;
859 ot->poll = ED_operator_posemode;
862 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
865 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
866 ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
869 /* -------------------------------------- */
872 * \note clone of #armature_select_mirror_exec keep in sync
874 static int pose_select_mirror_exec(bContext *C, wmOperator *op)
876 Object *ob_act = CTX_data_active_object(C);
877 Object *ob = BKE_object_pose_armature_get(ob_act);
879 bPoseChannel *pchan, *pchan_mirror_act = NULL;
880 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
881 const bool extend = RNA_boolean_get(op->ptr, "extend");
883 if ((ob && (ob->mode & OB_MODE_POSE)) == 0) {
884 return OPERATOR_CANCELLED;
889 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
890 const int flag = (pchan->bone->flag & BONE_SELECTED);
891 PBONE_PREV_FLAG_SET(pchan, flag);
894 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
895 if (PBONE_SELECTABLE(arm, pchan->bone)) {
896 bPoseChannel *pchan_mirror;
897 int flag_new = extend ? PBONE_PREV_FLAG_GET(pchan) : 0;
899 if ((pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) &&
900 (PBONE_VISIBLE(arm, pchan_mirror->bone)))
902 const int flag_mirror = PBONE_PREV_FLAG_GET(pchan_mirror);
903 flag_new |= flag_mirror;
905 if (pchan->bone == arm->act_bone) {
906 pchan_mirror_act = pchan_mirror;
909 /* skip all but the active or its mirror */
910 if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
915 pchan->bone->flag = (pchan->bone->flag & ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) | flag_new;
919 if (pchan_mirror_act) {
920 arm->act_bone = pchan_mirror_act->bone;
922 /* in weightpaint we select the associated vertex group too */
923 if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
924 ED_vgroup_select_by_name(ob_act, pchan_mirror_act->name);
925 DEG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
929 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
931 return OPERATOR_FINISHED;
934 void POSE_OT_select_mirror(wmOperatorType *ot)
937 ot->name = "Flip Active/Selected Bone";
938 ot->idname = "POSE_OT_select_mirror";
939 ot->description = "Mirror the bone selection";
942 ot->exec = pose_select_mirror_exec;
943 ot->poll = ED_operator_posemode;
946 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
949 RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
950 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");