Blender V4.5
pose_select.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include "DNA_action_types.h"
12#include "DNA_anim_types.h"
13#include "DNA_armature_types.h"
15#include "DNA_object_types.h"
16#include "DNA_scene_types.h"
17
18#include "BLI_listbase.h"
19#include "BLI_map.hh"
20#include "BLI_string.h"
21
22#include "BKE_action.hh"
23#include "BKE_armature.hh"
24#include "BKE_constraint.h"
25#include "BKE_context.hh"
26#include "BKE_layer.hh"
27#include "BKE_modifier.hh"
28#include "BKE_object.hh"
29#include "BKE_report.hh"
30
31#include "DEG_depsgraph.hh"
32
33#include "RNA_access.hh"
34#include "RNA_define.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_armature.hh"
40#include "ED_keyframing.hh"
41#include "ED_mesh.hh"
42#include "ED_object.hh"
43#include "ED_object_vgroup.hh"
44#include "ED_outliner.hh"
45#include "ED_screen.hh"
46#include "ED_select_utils.hh"
47#include "ED_view3d.hh"
48
49#include "ANIM_armature.hh"
50#include "ANIM_bonecolor.hh"
51#include "ANIM_keyingsets.hh"
52
53#include "armature_intern.hh"
54
55using blender::Span;
56using blender::Vector;
57
58/* ***************** Pose Select Utilities ********************* */
59
60/* NOTE: SEL_TOGGLE is assumed to have already been handled! */
61static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
62{
63 /* select pchan only if selectable, but deselect works always */
64 switch (select_mode) {
65 case SEL_SELECT:
66 if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
67 pchan->bone->flag |= BONE_SELECTED;
68 }
69 break;
70 case SEL_DESELECT:
72 break;
73 case SEL_INVERT:
74 if (pchan->bone->flag & BONE_SELECTED) {
76 }
77 else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
78 pchan->bone->flag |= BONE_SELECTED;
79 }
80 break;
81 }
82}
83
85{
87 bArmature *arm = static_cast<bArmature *>(ob->data);
90
91 if (arm->flag & ARM_HAS_VIZ_DEPS) {
92 /* mask modifier ('armature' mode), etc. */
94 }
95
97}
98
99void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool change_active)
100{
101 bArmature *arm;
102
103 /* sanity checks */
104 /* XXX: actually, we can probably still get away with no object - at most we have no updates */
105 if (ELEM(nullptr, ob, ob->pose, pchan, pchan->bone)) {
106 return;
107 }
108
109 arm = static_cast<bArmature *>(ob->data);
110
111 /* can only change selection state if bone can be modified */
112 if (PBONE_SELECTABLE(arm, pchan->bone)) {
113 /* change selection state - activate too if selected */
114 if (select) {
115 pchan->bone->flag |= BONE_SELECTED;
116 if (change_active) {
117 arm->act_bone = pchan->bone;
118 }
119 }
120 else {
121 pchan->bone->flag &= ~BONE_SELECTED;
122 if (change_active) {
123 arm->act_bone = nullptr;
124 }
125 }
126
127 /* TODO: select and activate corresponding vgroup? */
129 }
130}
131
133 ViewLayer *view_layer,
134 View3D *v3d,
135 Object *ob,
136 Bone *bone,
138{
139 bool found = false;
140 bool changed = false;
141
142 if (ob->pose) {
143 if (bone && ((bone->flag & BONE_UNSELECTABLE) == 0)) {
144 found = true;
145 }
146 }
147
148 if (params.sel_op == SEL_OP_SET) {
149 if ((found && params.select_passthrough) && (bone->flag & BONE_SELECTED)) {
150 found = false;
151 }
152 else if (found || params.deselect_all) {
153 /* Deselect everything. */
154 /* Don't use #BKE_object_pose_base_array_get_unique
155 * because we may be selecting from object mode. */
156 FOREACH_VISIBLE_BASE_BEGIN (scene, view_layer, v3d, base_iter) {
157 Object *ob_iter = base_iter->object;
158 if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) {
159 if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) {
161 }
162 }
163 }
165 changed = true;
166 }
167 }
168
169 if (found) {
170 BKE_view_layer_synced_ensure(scene, view_layer);
171 Object *ob_act = BKE_view_layer_active_object_get(view_layer);
172 BLI_assert(BKE_view_layer_edit_object_get(view_layer) == nullptr);
173
174 /* If the bone cannot be affected, don't do anything. */
175 bArmature *arm = static_cast<bArmature *>(ob->data);
176
177 /* Since we do unified select, we don't shift+select a bone if the
178 * armature object was not active yet.
179 * NOTE(@ideasman42): special exception for armature mode so we can do multi-select
180 * we could check for multi-select explicitly but think its fine to
181 * always give predictable behavior in weight paint mode. */
182 if ((ob_act == nullptr) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0))
183 {
184 /* When we are entering into posemode via toggle-select,
185 * from another active object - always select the bone. */
186 if (params.sel_op == SEL_OP_SET) {
187 /* Re-select the bone again later in this function. */
188 bone->flag &= ~BONE_SELECTED;
189 }
190 }
191
192 switch (params.sel_op) {
193 case SEL_OP_ADD: {
195 arm->act_bone = bone;
196 break;
197 }
198 case SEL_OP_SUB: {
200 break;
201 }
202 case SEL_OP_XOR: {
203 if (bone->flag & BONE_SELECTED) {
204 /* If not active, we make it active. */
205 if (bone != arm->act_bone) {
206 arm->act_bone = bone;
207 }
208 else {
210 }
211 }
212 else {
214 arm->act_bone = bone;
215 }
216 break;
217 }
218 case SEL_OP_SET: {
220 arm->act_bone = bone;
221 break;
222 }
223 case SEL_OP_AND: {
224 BLI_assert_unreachable(); /* Doesn't make sense for picking. */
225 break;
226 }
227 }
228
229 if (ob_act) {
230 /* In weight-paint we select the associated vertex group too. */
231 if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) {
232 if (bone == arm->act_bone) {
235 }
236 }
237 /* If there are some dependencies for visualizing armature state
238 * (e.g. Mask Modifier in 'Armature' mode), force update.
239 */
240 else if (arm->flag & ARM_HAS_VIZ_DEPS) {
241 /* NOTE: ob not ob_act here is intentional - it's the source of the
242 * bones being selected [#37247].
243 */
245 }
246
247 /* Tag armature for copy-on-evaluation update (since act_bone is in armature not object). */
249 }
250
251 changed = true;
252 }
253
254 return changed || found;
255}
256
258 ViewLayer *view_layer,
259 View3D *v3d,
260 Base *base,
261 const GPUSelectResult *hit_results,
262 const int hits,
264 bool do_nearest)
265{
266 Object *ob = base->object;
267 Bone *nearBone;
268
269 if (!ob || !ob->pose) {
270 return false;
271 }
272
273 /* Callers happen to already get the active base */
274 Base *base_dummy = nullptr;
276 {base}, hit_results, hits, true, do_nearest, &base_dummy);
277
278 return ED_armature_pose_select_pick_bone(scene, view_layer, v3d, ob, nearBone, params);
279}
280
282 ViewLayer *view_layer,
283 Base *base_select)
284{
285 BLI_assert(base_select && (base_select->object->type == OB_ARMATURE));
286 BKE_view_layer_synced_ensure(scene, view_layer);
287 Object *ob_active = BKE_view_layer_active_object_get(view_layer);
288 BLI_assert(ob_active && (ob_active->mode & OB_MODE_ALL_WEIGHT_PAINT));
289
290 VirtualModifierData virtual_modifier_data;
291 ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob_active, &virtual_modifier_data);
292 for (; md; md = md->next) {
293 if (md->type == eModifierType_Armature) {
294 ArmatureModifierData *amd = reinterpret_cast<ArmatureModifierData *>(md);
295 Object *ob_arm = amd->object;
296 if (ob_arm != nullptr) {
297 Base *base_arm = BKE_view_layer_base_find(view_layer, ob_arm);
298 if ((base_arm != nullptr) && (base_arm != base_select) && (base_arm->flag & BASE_SELECTED))
299 {
301 }
302 }
303 }
304 }
305 if ((base_select->flag & BASE_SELECTED) == 0) {
307 }
308}
309
310bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
311{
312 bArmature *arm = static_cast<bArmature *>(ob->data);
313
314 /* we call this from outliner too */
315 if (ob->pose == nullptr) {
316 return false;
317 }
318
319 /* Determine if we're selecting or deselecting */
320 if (select_mode == SEL_TOGGLE) {
321 select_mode = SEL_SELECT;
322 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
323 if (ignore_visibility || blender::animrig::bone_is_visible_pchan(arm, pchan)) {
324 if (pchan->bone->flag & BONE_SELECTED) {
325 select_mode = SEL_DESELECT;
326 break;
327 }
328 }
329 }
330 }
331
332 /* Set the flags accordingly */
333 bool changed = false;
334 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
335 /* ignore the pchan if it isn't visible or if its selection cannot be changed */
336 if (ignore_visibility || blender::animrig::bone_is_visible_pchan(arm, pchan)) {
337 int flag_prev = pchan->bone->flag;
338 pose_do_bone_select(pchan, select_mode);
339 changed = (changed || flag_prev != pchan->bone->flag);
340 }
341 }
342 return changed;
343}
344
345static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
346{
347 bArmature *arm = static_cast<bArmature *>(ob->data);
348 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
349 if (ignore_visibility || blender::animrig::bone_is_visible_pchan(arm, pchan)) {
350 if (pchan->bone->flag & BONE_SELECTED) {
351 return true;
352 }
353 }
354 }
355 return false;
356}
357
358static bool ed_pose_is_any_selected_multi(const Span<Base *> bases, bool ignore_visibility)
359{
360 for (Base *base : bases) {
361 Object *ob_iter = base->object;
362 if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
363 return true;
364 }
365 }
366 return false;
367}
368
370 int select_mode,
371 const bool ignore_visibility)
372{
373 if (select_mode == SEL_TOGGLE) {
374 select_mode = ed_pose_is_any_selected_multi(bases, ignore_visibility) ? SEL_DESELECT :
376 }
377
378 bool changed_multi = false;
379 for (Base *base : bases) {
380 Object *ob_iter = base->object;
381 if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
383 changed_multi = true;
384 }
385 }
386 return changed_multi;
387}
388
389bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
390{
393
395 return ED_pose_deselect_all_multi_ex(bases, select_mode, ignore_visibility);
396}
397
398/* ***************** Selections ********************** */
399
400static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
401{
402 /* stop when unconnected child is encountered, or when unselectable bone is encountered */
403 if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE)) {
404 return;
405 }
406
407 if (extend) {
408 bone->flag &= ~BONE_SELECTED;
409 }
410 else {
411 bone->flag |= BONE_SELECTED;
412 }
413
414 LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) {
415 selectconnected_posebonechildren(ob, curBone, extend);
416 }
417}
418
419/* within active object context */
420/* previously known as "selectconnected_posearmature" */
422 wmOperator *op,
423 const wmEvent *event)
424{
425 Bone *bone, *curBone, *next = nullptr;
426 const bool extend = RNA_boolean_get(op->ptr, "extend");
427
429
430 Base *base = nullptr;
431 bone = ED_armature_pick_bone(C, event->mval, !extend, &base);
432
433 if (!bone) {
434 return OPERATOR_CANCELLED;
435 }
436
437 /* Select parents */
438 for (curBone = bone; curBone; curBone = next) {
439 /* ignore bone if cannot be selected */
440 if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
441 if (extend) {
442 curBone->flag &= ~BONE_SELECTED;
443 }
444 else {
445 curBone->flag |= BONE_SELECTED;
446 }
447
448 if (curBone->flag & BONE_CONNECTED) {
449 next = curBone->parent;
450 }
451 else {
452 next = nullptr;
453 }
454 }
455 else {
456 next = nullptr;
457 }
458 }
459
460 /* Select children */
461 LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) {
462 selectconnected_posebonechildren(base->object, curBone, extend);
463 }
464
466
468
469 return OPERATOR_FINISHED;
470}
471
476
478{
479 PropertyRNA *prop;
480
481 /* identifiers */
482 ot->name = "Select Connected";
483 ot->idname = "POSE_OT_select_linked_pick";
484 ot->description = "Select bones linked by parent/child connections under the mouse cursor";
485
486 /* callbacks */
487 /* leave 'exec' unset */
490
491 /* flags */
493
494 /* props */
495 prop = RNA_def_boolean(ot->srna,
496 "extend",
497 false,
498 "Extend",
499 "Extend selection instead of deselecting everything first");
501}
502
504{
505 Bone *curBone, *next = nullptr;
506
507 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
508 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
509 continue;
510 }
511
512 bArmature *arm = static_cast<bArmature *>(ob->data);
513
514 /* Select parents */
515 for (curBone = pchan->bone; curBone; curBone = next) {
516 if (PBONE_SELECTABLE(arm, curBone)) {
517 curBone->flag |= BONE_SELECTED;
518
519 if (curBone->flag & BONE_CONNECTED) {
520 next = curBone->parent;
521 }
522 else {
523 next = nullptr;
524 }
525 }
526 else {
527 next = nullptr;
528 }
529 }
530
531 /* Select children */
532 LISTBASE_FOREACH (Bone *, curBone, &pchan->bone->childbase) {
533 selectconnected_posebonechildren(ob, curBone, false);
534 }
536 }
538
540
541 return OPERATOR_FINISHED;
542}
543
545{
546 /* identifiers */
547 ot->name = "Select Connected";
548 ot->idname = "POSE_OT_select_linked";
549 ot->description = "Select all bones linked by parent/child connections to the current selection";
550
551 /* callbacks */
553 ot->poll = ED_operator_posemode;
554
555 /* flags */
557}
558
559/* -------------------------------------- */
560
562{
563 int action = RNA_enum_get(op->ptr, "action");
564
565 Scene *scene = CTX_data_scene(C);
566 int multipaint = scene->toolsettings->multipaint;
567
568 if (action == SEL_TOGGLE) {
569 action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
570 }
571
572 Object *ob_prev = nullptr;
573
574 /* Set the flags. */
575 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
576 bArmature *arm = static_cast<bArmature *>(ob->data);
577 pose_do_bone_select(pchan, action);
578
579 if (ob_prev != ob) {
580 /* Weight-paint or mask modifiers need depsgraph updates. */
581 if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
583 }
584 /* need to tag armature for cow updates, or else selection doesn't update */
586 ob_prev = ob;
587 }
588 }
590
592
594
595 return OPERATOR_FINISHED;
596}
597
599{
600 /* identifiers */
601 ot->name = "(De)select All";
602 ot->idname = "POSE_OT_select_all";
603 ot->description = "Toggle selection status of all bones";
604
605 /* API callbacks. */
607 ot->poll = ED_operator_posemode;
608
609 /* flags */
611
613}
614
615/* -------------------------------------- */
616
618{
620 bArmature *arm = static_cast<bArmature *>(ob->data);
621 bPoseChannel *pchan, *parent;
622
623 /* Determine if there is an active bone */
625 if (pchan) {
626 parent = pchan->parent;
627 if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
628 parent->bone->flag |= BONE_SELECTED;
629 arm->act_bone = parent->bone;
630 }
631 else {
632 return OPERATOR_CANCELLED;
633 }
634 }
635 else {
636 return OPERATOR_CANCELLED;
637 }
638
640
642 return OPERATOR_FINISHED;
643}
644
646{
647 /* identifiers */
648 ot->name = "Select Parent Bone";
649 ot->idname = "POSE_OT_select_parent";
650 ot->description = "Select bones that are parents of the currently selected bones";
651
652 /* API callbacks. */
654 ot->poll = ED_operator_posemode;
655
656 /* flags */
658}
659
660/* -------------------------------------- */
661
663{
664 bool found = false;
665
666 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
667 if (pchan->bone->flag & BONE_SELECTED) {
668 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
669 ListBase targets = {nullptr, nullptr};
670 if (BKE_constraint_targets_get(con, &targets)) {
671 LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
672 Object *ob = ct->tar;
673
674 /* Any armature that is also in pose mode should be selected. */
675 if ((ct->subtarget[0] != '\0') && (ob != nullptr) && (ob->type == OB_ARMATURE) &&
676 (ob->mode == OB_MODE_POSE))
677 {
678 bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
679 if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
682 found = true;
683 }
684 }
685 }
686
687 BKE_constraint_targets_flush(con, &targets, true);
688 }
689 }
690 }
691 }
693
694 if (!found) {
695 return OPERATOR_CANCELLED;
696 }
697
699
700 return OPERATOR_FINISHED;
701}
702
704{
705 /* identifiers */
706 ot->name = "Select Constraint Target";
707 ot->idname = "POSE_OT_select_constraint_target";
708 ot->description = "Select bones used as targets for the currently selected bones";
709
710 /* API callbacks. */
712 ot->poll = ED_operator_posemode;
713
714 /* flags */
716}
717
718/* -------------------------------------- */
719
720/* No need to convert to multi-objects. Just like we keep the non-active bones
721 * selected we then keep the non-active objects untouched (selected/unselected). */
723{
725 bArmature *arm = static_cast<bArmature *>(ob->data);
726 bPoseChannel *pchan_act;
727 int direction = RNA_enum_get(op->ptr, "direction");
728 const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
729 bool changed = false;
730
732 if (pchan_act == nullptr) {
733 return OPERATOR_CANCELLED;
734 }
735
736 if (direction == BONE_SELECT_PARENT) {
737 if (pchan_act->parent) {
738 Bone *bone_parent;
739 bone_parent = pchan_act->parent->bone;
740
741 if (PBONE_SELECTABLE(arm, bone_parent)) {
742 if (!add_to_sel) {
743 pchan_act->bone->flag &= ~BONE_SELECTED;
744 }
745 bone_parent->flag |= BONE_SELECTED;
746 arm->act_bone = bone_parent;
747
748 changed = true;
749 }
750 }
751 }
752 else { /* direction == BONE_SELECT_CHILD */
753 Bone *bone_child = nullptr;
754 int pass;
755
756 /* first pass, only connected bones (the logical direct child) */
757 for (pass = 0; pass < 2 && (bone_child == nullptr); pass++) {
758 LISTBASE_FOREACH (bPoseChannel *, pchan_iter, &ob->pose->chanbase) {
759 /* possible we have multiple children, some invisible */
760 if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
761 if (pchan_iter->parent == pchan_act) {
762 if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
763 bone_child = pchan_iter->bone;
764 break;
765 }
766 }
767 }
768 }
769 }
770
771 if (bone_child) {
772 arm->act_bone = bone_child;
773
774 if (!add_to_sel) {
775 pchan_act->bone->flag &= ~BONE_SELECTED;
776 }
777 bone_child->flag |= BONE_SELECTED;
778
779 changed = true;
780 }
781 }
782
783 if (changed == false) {
784 return OPERATOR_CANCELLED;
785 }
786
788
790
791 return OPERATOR_FINISHED;
792}
793
795{
796 static const EnumPropertyItem direction_items[] = {
797 {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
798 {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
799 {0, nullptr, 0, nullptr, nullptr},
800 };
801
802 /* identifiers */
803 ot->name = "Select Hierarchy";
804 ot->idname = "POSE_OT_select_hierarchy";
805 ot->description = "Select immediate parent/children of selected bones";
806
807 /* API callbacks. */
809 ot->poll = ED_operator_posemode;
810
811 /* flags */
813
814 /* props */
815 ot->prop = RNA_def_enum(
816 ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
817 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
818}
819
820/* -------------------------------------- */
821
822/* Modes for the `select_grouped` operator. */
832
833static bool pose_select_same_color(bContext *C, const bool extend)
834{
835 /* Get a set of all the colors of the selected bones. */
837 blender::Set<Object *> updated_objects;
838 bool changed_any_selection = false;
839
840 /* Old approach that we may want to reinstate behind some option at some point. This will match
841 * against the colors of all selected bones, instead of just the active one. It also explains why
842 * there is a set of colors to begin with.
843 *
844 * CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) {
845 * auto color = blender::animrig::ANIM_bonecolor_posebone_get(pchan);
846 * used_colors.add(color);
847 * }
848 * CTX_DATA_END;
849 */
850 if (!extend) {
851 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
852 pchan->bone->flag &= ~BONE_SELECTED;
853 updated_objects.add(ob);
854 changed_any_selection = true;
855 }
857 }
858
859 /* Use the color of the active pose bone. */
860 bPoseChannel *active_pose_bone = CTX_data_active_pose_bone(C);
861 auto color = blender::animrig::ANIM_bonecolor_posebone_get(active_pose_bone);
862 used_colors.add(color);
863
864 /* Select all visible bones that have the same color. */
865 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
866 Bone *bone = pchan->bone;
867 if (bone->flag & (BONE_UNSELECTABLE | BONE_SELECTED)) {
868 /* Skip bones that are unselectable or already selected. */
869 continue;
870 }
871
873 if (!used_colors.contains(color)) {
874 continue;
875 }
876
877 bone->flag |= BONE_SELECTED;
878 changed_any_selection = true;
879 updated_objects.add(ob);
880 }
882
883 if (!changed_any_selection) {
884 return false;
885 }
886
887 for (Object *ob : updated_objects) {
889 }
890 return true;
891}
892
893static bool pose_select_same_collection(bContext *C, const bool extend)
894{
895 bool changed_any_selection = false;
896 blender::Set<Object *> updated_objects;
897
898 /* Refuse to do anything if there is no active pose bone. */
900 if (!active_pchan) {
901 return false;
902 }
903
904 if (!extend) {
905 /* Deselect all the bones. */
906 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
907 pchan->bone->flag &= ~BONE_SELECTED;
908 updated_objects.add(ob);
909 changed_any_selection = true;
910 }
912 }
913
914 /* Build a set of bone collection names, to allow cross-Armature selection. */
915 blender::Set<std::string> collection_names;
916 LISTBASE_FOREACH (BoneCollectionReference *, bcoll_ref, &active_pchan->bone->runtime.collections)
917 {
918 collection_names.add(bcoll_ref->bcoll->name);
919 }
920
921 /* Select all bones that match any of the collection names. */
922 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
923 Bone *bone = pchan->bone;
924 if (bone->flag & (BONE_UNSELECTABLE | BONE_SELECTED)) {
925 continue;
926 }
927
929 if (!collection_names.contains(bcoll_ref->bcoll->name)) {
930 continue;
931 }
932
933 bone->flag |= BONE_SELECTED;
934 changed_any_selection = true;
935 updated_objects.add(ob);
936 }
937 }
939
940 for (Object *ob : updated_objects) {
942 }
943
944 return changed_any_selection;
945}
946
947/* Useful to get the selection before modifying it. */
949{
950 blender::Set<bPoseChannel *> selected_pose_bones;
951 bArmature *arm = static_cast<bArmature *>((pose_object) ? pose_object->data : nullptr);
952 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
953 if (PBONE_SELECTED(arm, pchan->bone)) {
954 selected_pose_bones.add(pchan);
955 }
956 }
957 return selected_pose_bones;
958}
959
961 const blender::Set<bPoseChannel *> &potential_parents)
962{
963 bPoseChannel *bone_iter = &bone;
964 while (bone_iter) {
965 if (potential_parents.contains(bone_iter)) {
966 return true;
967 }
968 bone_iter = bone_iter->parent;
969 }
970 return false;
971}
972
974{
975 for (bPoseChannel *pose_bone : pose_bones) {
976 if (!pose_bone) {
977 /* There may be a nullptr in the set if selecting siblings of root bones. */
978 continue;
979 }
980 pose_bone->bone->flag &= ~BONE_SELECTED;
981 }
982}
983
984/* Selects children of currently selected bones in all objects in pose mode. If `all` is true, a
985 * bone will be selected if any bone in it's parent hierarchy is selected. If false, only bones
986 * whose direct parent is selected are changed. */
987static bool pose_select_children(bContext *C, const bool all, const bool extend)
988{
991
992 bool changed_any_selection = false;
993
994 for (Object *pose_object : objects) {
995 bArmature *arm = static_cast<bArmature *>(pose_object->data);
996 BLI_assert(arm);
997 blender::Set<bPoseChannel *> selected_pose_bones = get_selected_pose_bones(pose_object);
998 if (!extend) {
999 deselect_pose_bones(selected_pose_bones);
1000 }
1001 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1002 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1003 continue;
1004 }
1005 if (all) {
1006 if (pose_bone_is_below_one_of(*pchan, selected_pose_bones)) {
1008 changed_any_selection = true;
1009 }
1010 }
1011 else {
1012 if (selected_pose_bones.contains(pchan->parent)) {
1014 changed_any_selection = true;
1015 }
1016 }
1017 }
1018 ED_pose_bone_select_tag_update(pose_object);
1019 }
1020
1021 return changed_any_selection;
1022}
1023
1024static bool pose_select_parents(bContext *C, const bool extend)
1025{
1028
1029 bool changed_any_selection = false;
1030 for (Object *pose_object : objects) {
1031 bArmature *arm = static_cast<bArmature *>(pose_object->data);
1032 BLI_assert(arm);
1033 blender::Set<bPoseChannel *> selected_pose_bones = get_selected_pose_bones(pose_object);
1034 if (!extend) {
1035 deselect_pose_bones(selected_pose_bones);
1036 }
1037 for (bPoseChannel *pchan : selected_pose_bones) {
1038 if (!pchan->parent) {
1039 continue;
1040 }
1041 if (!PBONE_SELECTABLE(arm, pchan->parent->bone)) {
1042 continue;
1043 }
1044 pose_do_bone_select(pchan->parent, SEL_SELECT);
1045 changed_any_selection = true;
1046 }
1047 ED_pose_bone_select_tag_update(pose_object);
1048 }
1049 return changed_any_selection;
1050}
1051
1052static bool pose_select_siblings(bContext *C, const bool extend)
1053{
1056
1057 bool changed_any_selection = false;
1058 for (Object *pose_object : objects) {
1059 bArmature *arm = static_cast<bArmature *>(pose_object->data);
1060 BLI_assert(arm);
1061 blender::Set<bPoseChannel *> parents_of_selected;
1062 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1063 if (PBONE_SELECTED(arm, pchan->bone)) {
1064 parents_of_selected.add(pchan->parent);
1065 }
1066 }
1067 if (!extend) {
1068 deselect_pose_bones(parents_of_selected);
1069 }
1070 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1071 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1072 continue;
1073 }
1074 /* Checking if the bone is already selected so `changed_any_selection` stays true to its
1075 * word. */
1076 if (parents_of_selected.contains(pchan->parent) && !PBONE_SELECTED(arm, pchan->bone)) {
1078 changed_any_selection = true;
1079 }
1080 }
1081 ED_pose_bone_select_tag_update(pose_object);
1082 }
1083 return changed_any_selection;
1084}
1085
1087{
1088 using namespace blender::animrig;
1089 Scene *scene = CTX_data_scene(C);
1090 ViewLayer *view_layer = CTX_data_view_layer(C);
1091 bool changed_multi = false;
1093
1094 /* sanity checks: validate Keying Set and object */
1095 if (ks == nullptr) {
1096 BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
1097 return false;
1098 }
1099 if (validate_keyingset(C, nullptr, ks) != ModifyKeyReturn::SUCCESS) {
1100 if (ks->paths.first == nullptr) {
1101 if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1103 RPT_ERROR,
1104 "Use another Keying Set, as the active one depends on the currently "
1105 "selected items or cannot find any targets due to unsuitable context");
1106 }
1107 else {
1108 BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
1109 }
1110 }
1111 return false;
1112 }
1113
1114 /* if not extending selection, deselect all selected first */
1115 if (extend == false) {
1116 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
1117 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
1118 pchan->bone->flag &= ~BONE_SELECTED;
1119 }
1120 }
1122 }
1123
1125
1126 for (const int ob_index : objects.index_range()) {
1127 Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
1128 bArmature *arm = static_cast<bArmature *>((ob) ? ob->data : nullptr);
1129 bPose *pose = (ob) ? ob->pose : nullptr;
1130 bool changed = false;
1131
1132 /* Sanity checks. */
1133 if (ELEM(nullptr, ob, pose, arm)) {
1134 continue;
1135 }
1136
1137 /* iterate over elements in the Keying Set, setting selection depending on whether
1138 * that bone is visible or not...
1139 */
1140 LISTBASE_FOREACH (KS_Path *, ksp, &ks->paths) {
1141 /* only items related to this object will be relevant */
1142 if ((ksp->id == &ob->id) && (ksp->rna_path != nullptr)) {
1143 bPoseChannel *pchan = nullptr;
1144 char boneName[sizeof(pchan->name)];
1145 if (!BLI_str_quoted_substr(ksp->rna_path, "bones[", boneName, sizeof(boneName))) {
1146 continue;
1147 }
1148 pchan = BKE_pose_channel_find_name(pose, boneName);
1149
1150 if (pchan) {
1151 /* select if bone is visible and can be affected */
1152 if (PBONE_SELECTABLE(arm, pchan->bone)) {
1153 pchan->bone->flag |= BONE_SELECTED;
1154 changed = true;
1155 }
1156 }
1157 }
1158 }
1159
1160 if (changed || !extend) {
1162 changed_multi = true;
1163 }
1164 }
1165
1166 return changed_multi;
1167}
1168
1170{
1172 const SelectRelatedMode mode = SelectRelatedMode(RNA_enum_get(op->ptr, "type"));
1173 const bool extend = RNA_boolean_get(op->ptr, "extend");
1174 bool changed = false;
1175
1176 /* sanity check */
1177 if (ob->pose == nullptr) {
1178 return OPERATOR_CANCELLED;
1179 }
1180
1181 /* selection types */
1182 switch (mode) {
1184 changed = pose_select_same_collection(C, extend);
1185 break;
1186
1188 changed = pose_select_same_color(C, extend);
1189 break;
1190
1192 changed = pose_select_same_keyingset(C, op->reports, extend);
1193 break;
1194
1196 changed = pose_select_children(C, true, extend);
1197 break;
1198
1200 changed = pose_select_children(C, false, extend);
1201 break;
1202
1204 changed = pose_select_parents(C, extend);
1205 break;
1206
1208 changed = pose_select_siblings(C, extend);
1209 break;
1210
1211 default:
1212 printf("pose_select_grouped() - Unknown selection type %d\n", int(mode));
1213 break;
1214 }
1215
1216 /* report done status */
1217 if (changed) {
1219
1220 return OPERATOR_FINISHED;
1221 }
1222 return OPERATOR_CANCELLED;
1223}
1224
1226{
1227 static const EnumPropertyItem prop_select_grouped_types[] = {
1229 "COLLECTION",
1230 0,
1231 "Collection",
1232 "Same collections as the active bone"},
1233 {int(SelectRelatedMode::SAME_COLOR), "COLOR", 0, "Color", "Same color as the active bone"},
1235 "KEYINGSET",
1236 0,
1237 "Keying Set",
1238 "All bones affected by active Keying Set"},
1240 "CHILDREN",
1241 0,
1242 "Children",
1243 "Select all children of currently selected bones"},
1245 "CHILDREN_IMMEDIATE",
1246 0,
1247 "Immediate Children",
1248 "Select direct children of currently selected bones"},
1250 "PARENT",
1251 0,
1252 "Parents",
1253 "Select the parents of currently selected bones"},
1255 "SIBILINGS",
1256 0,
1257 "Siblings",
1258 "Select all bones that have the same parent as currently selected bones"},
1259 {0, nullptr, 0, nullptr, nullptr},
1260 };
1261
1262 /* identifiers */
1263 ot->name = "Select Grouped";
1264 ot->description = "Select all visible bones grouped by similar properties";
1265 ot->idname = "POSE_OT_select_grouped";
1266
1267 /* API callbacks. */
1268 ot->invoke = WM_menu_invoke;
1270 ot->poll = ED_operator_posemode; /* TODO: expand to support edit mode as well. */
1271
1272 /* flags */
1273 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1274
1275 /* properties */
1276 RNA_def_boolean(ot->srna,
1277 "extend",
1278 false,
1279 "Extend",
1280 "Extend selection instead of deselecting everything first");
1281 ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
1282}
1283
1284/* -------------------------------------- */
1285
1286/* Add the given selection flags to the bone flags. */
1287static void bone_selection_flags_add(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
1288{
1289 pchan->bone->flag |= (new_selection_flags & BONE_SELECTED);
1290}
1291
1292/* Set the bone flags to the given selection flags. */
1293static void bone_selection_flags_set(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
1294{
1296 pchan->bone->flag |= (new_selection_flags & BONE_SELECTED);
1297}
1298
1303{
1304 const Scene *scene = CTX_data_scene(C);
1305 ViewLayer *view_layer = CTX_data_view_layer(C);
1306 Object *ob_active = CTX_data_active_object(C);
1307
1308 const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
1309 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
1310 const bool extend = RNA_boolean_get(op->ptr, "extend");
1311
1312 const auto set_bone_selection_flags = extend ? bone_selection_flags_add :
1314
1316 for (Object *ob : objects) {
1317 bArmature *arm = static_cast<bArmature *>(ob->data);
1318 bPoseChannel *pchan_mirror_act = nullptr;
1319
1320 /* Remember the pre-mirroring selection flags of the bones. */
1321 blender::Map<bPoseChannel *, eBone_Flag> old_selection_flags;
1322 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1323 /* Treat invisible bones as deselected. */
1324 const int flags = blender::animrig::bone_is_visible_pchan(arm, pchan) ? pchan->bone->flag :
1325 0;
1326
1327 old_selection_flags.add_new(pchan, eBone_Flag(flags));
1328 }
1329
1330 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1331 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1332 continue;
1333 }
1334
1335 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
1336 if (!pchan_mirror) {
1337 /* If a bone cannot be mirrored, keep its flags as-is. This makes it possible to select
1338 * the spine and an arm, and still flip the selection to the other arm (without losing
1339 * the selection on the spine). */
1340 continue;
1341 }
1342
1343 if (pchan->bone == arm->act_bone) {
1344 pchan_mirror_act = pchan_mirror;
1345 }
1346
1347 /* If active-only, don't touch unrelated bones. */
1348 if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
1349 continue;
1350 }
1351
1352 const eBone_Flag flags_mirror = old_selection_flags.lookup(pchan_mirror);
1353 set_bone_selection_flags(pchan, flags_mirror);
1354 }
1355
1356 if (pchan_mirror_act) {
1357 arm->act_bone = pchan_mirror_act->bone;
1358
1359 /* In weight-paint we select the associated vertex group too. */
1360 if (is_weight_paint) {
1361 blender::ed::object::vgroup_select_by_name(ob_active, pchan_mirror_act->name);
1363 }
1364 }
1365
1367
1368 /* Need to tag armature for cow updates, or else selection doesn't update. */
1370 }
1371
1373
1374 return OPERATOR_FINISHED;
1375}
1376
1378{
1379 /* identifiers */
1380 ot->name = "Select Mirror";
1381 ot->idname = "POSE_OT_select_mirror";
1382 ot->description = "Mirror the bone selection";
1383
1384 /* API callbacks. */
1386 ot->poll = ED_operator_posemode;
1387
1388 /* flags */
1389 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1390
1391 /* properties */
1393 ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
1394 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
1395}
Functions to deal with Armatures.
C++ part of the BoneColor DNA struct.
Functionality to interact with keying sets.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
bPoseChannel * BKE_pose_channel_get_mirrored(const bPose *pose, const char *name) ATTR_WARN_UNUSED_RESULT
bPoseChannel * BKE_pose_channel_active_if_bonecoll_visible(Object *ob) ATTR_WARN_UNUSED_RESULT
#define PBONE_SELECTED(arm, bone)
#define PBONE_SELECTABLE(arm, bone)
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
#define CTX_DATA_BEGIN_WITH_ID(C, Type, instance, member, Type_id, instance_id)
bPoseChannel * CTX_data_active_pose_bone(const bContext *C)
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
#define CTX_DATA_COUNT(C, member)
Scene * CTX_data_scene(const bContext *C)
#define CTX_DATA_END
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
#define FOREACH_VISIBLE_BASE_END
Definition BKE_layer.hh:417
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
#define FOREACH_VISIBLE_BASE_BEGIN(_scene, _view_layer, _v3d, _instance)
Definition BKE_layer.hh:404
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
ModifierData * BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *data)
General operations, lookup, etc. for blender objects.
blender::Vector< Base * > BKE_object_pose_base_array_get_unique(const Scene *scene, ViewLayer *view_layer, View3D *v3d)
Object * BKE_object_pose_armature_get(Object *ob)
blender::Vector< Object * > BKE_object_pose_array_get_unique(const Scene *scene, ViewLayer *view_layer, View3D *v3d)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.cc:531
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ KEYINGSET_ABSOLUTE
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_HIDDEN_P
@ BONE_TIPSEL
@ BONE_CONNECTED
@ ARM_HAS_VIZ_DEPS
@ eModifierType_Armature
#define OB_MODE_ALL_WEIGHT_PAINT
@ OB_MODE_WEIGHT_PAINT
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define BASE_SELECTED(v3d, base)
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define BONE_SELECT_CHILD
#define BONE_SELECT_PARENT
void ED_outliner_select_sync_from_pose_bone_tag(bContext *C)
bool ED_operator_view3d_active(bContext *C)
bool ED_operator_posemode(bContext *C)
@ SEL_OP_ADD
@ SEL_OP_SUB
@ SEL_OP_SET
@ SEL_OP_AND
@ SEL_OP_XOR
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void view3d_operator_needs_gpu(const bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
ReportList * reports
Definition WM_types.hh:1025
#define ND_BONE_SELECT
Definition WM_types.hh:457
#define NC_OBJECT
Definition WM_types.hh:376
Bone * ED_armature_pick_bone_from_selectbuffer(blender::Span< Base * > bases, const GPUSelectResult *hit_results, int hits, bool findunsel, bool do_nearest, Base **r_base)
Bone * ED_armature_pick_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
BPy_StructRNA * depsgraph
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
IndexRange index_range() const
#define select(A, B, C)
bool all(VecOp< bool, D >) RET
#define printf(...)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static ulong * next
KeyingSet * scene_get_active_keyingset(const Scene *scene)
const BoneColor & ANIM_bonecolor_posebone_get(const bPoseChannel *pose_bone)
Definition bonecolor.cc:90
bool bone_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan)
ModifyKeyReturn validate_keyingset(bContext *C, blender::Vector< PointerRNA > *sources, KeyingSet *keyingset)
void base_select(Base *base, eObjectSelect_Mode mode)
void vgroup_select_by_name(Object *ob, const char *name)
static void bone_selection_flags_add(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
static wmOperatorStatus pose_select_linked_exec(bContext *C, wmOperator *)
static bool pose_select_same_collection(bContext *C, const bool extend)
static bool pose_select_siblings(bContext *C, const bool extend)
void POSE_OT_select_parent(wmOperatorType *ot)
static bool pose_select_children(bContext *C, const bool all, const bool extend)
static bool pose_select_parents(bContext *C, const bool extend)
SelectRelatedMode
static wmOperatorStatus pose_select_grouped_exec(bContext *C, wmOperator *op)
static blender::Set< bPoseChannel * > get_selected_pose_bones(Object *pose_object)
void ED_armature_pose_select_in_wpaint_mode(const Scene *scene, ViewLayer *view_layer, Base *base_select)
static wmOperatorStatus pose_select_constraint_target_exec(bContext *C, wmOperator *)
bool ED_armature_pose_select_pick_bone(const Scene *scene, ViewLayer *view_layer, View3D *v3d, Object *ob, Bone *bone, const SelectPick_Params &params)
static void deselect_pose_bones(const blender::Set< bPoseChannel * > &pose_bones)
static bool ed_pose_is_any_selected_multi(const Span< Base * > bases, bool ignore_visibility)
void POSE_OT_select_hierarchy(wmOperatorType *ot)
void POSE_OT_select_grouped(wmOperatorType *ot)
void POSE_OT_select_linked_pick(wmOperatorType *ot)
static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
static wmOperatorStatus pose_select_parent_exec(bContext *C, wmOperator *)
void ED_pose_bone_select_tag_update(Object *ob)
bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibility)
void POSE_OT_select_mirror(wmOperatorType *ot)
bool ED_pose_deselect_all_multi_ex(const Span< Base * > bases, int select_mode, const bool ignore_visibility)
static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
void POSE_OT_select_all(wmOperatorType *ot)
void POSE_OT_select_constraint_target(wmOperatorType *ot)
static bool pose_select_linked_pick_poll(bContext *C)
static void bone_selection_flags_set(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
bool ED_armature_pose_select_pick_with_buffer(const Scene *scene, ViewLayer *view_layer, View3D *v3d, Base *base, const GPUSelectResult *hit_results, const int hits, const SelectPick_Params &params, bool do_nearest)
static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool extend)
static wmOperatorStatus pose_select_hierarchy_exec(bContext *C, wmOperator *op)
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool change_active)
static wmOperatorStatus pose_select_mirror_exec(bContext *C, wmOperator *op)
static bool pose_bone_is_below_one_of(bPoseChannel &bone, const blender::Set< bPoseChannel * > &potential_parents)
static wmOperatorStatus pose_de_select_all_exec(bContext *C, wmOperator *op)
void POSE_OT_select_linked(wmOperatorType *ot)
static bool pose_select_same_color(bContext *C, const bool extend)
static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
static wmOperatorStatus pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
short flag
struct Object * object
Bone_Runtime runtime
struct Bone * parent
char name[64]
ListBase childbase
ListBase paths
void * first
struct ModifierData * next
struct bPose * pose
struct ToolSettings * toolsettings
Scene * scene
Definition ED_view3d.hh:73
ViewLayer * view_layer
Definition ED_view3d.hh:74
View3D * v3d
Definition ED_view3d.hh:78
struct Bone * bone
struct bPoseChannel * parent
ListBase chanbase
int mval[2]
Definition WM_types.hh:760
struct ReportList * reports
struct PointerRNA * ptr
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)