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 if (!pchan->bone) {
336 /* Ignore the pchan if it doesn't have a corresponding bone. */
337 continue;
338 }
339 /* ignore the pchan if it isn't visible or if its selection cannot be changed */
340 if (ignore_visibility || blender::animrig::bone_is_visible_pchan(arm, pchan)) {
341 int flag_prev = pchan->bone->flag;
342 pose_do_bone_select(pchan, select_mode);
343 changed = (changed || flag_prev != pchan->bone->flag);
344 }
345 }
346 return changed;
347}
348
349static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
350{
351 bArmature *arm = static_cast<bArmature *>(ob->data);
352 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
353 if (ignore_visibility || blender::animrig::bone_is_visible_pchan(arm, pchan)) {
354 if (pchan->bone->flag & BONE_SELECTED) {
355 return true;
356 }
357 }
358 }
359 return false;
360}
361
362static bool ed_pose_is_any_selected_multi(const Span<Base *> bases, bool ignore_visibility)
363{
364 for (Base *base : bases) {
365 Object *ob_iter = base->object;
366 if (ed_pose_is_any_selected(ob_iter, ignore_visibility)) {
367 return true;
368 }
369 }
370 return false;
371}
372
374 int select_mode,
375 const bool ignore_visibility)
376{
377 if (select_mode == SEL_TOGGLE) {
378 select_mode = ed_pose_is_any_selected_multi(bases, ignore_visibility) ? SEL_DESELECT :
380 }
381
382 bool changed_multi = false;
383 for (Base *base : bases) {
384 Object *ob_iter = base->object;
385 if (ED_pose_deselect_all(ob_iter, select_mode, ignore_visibility)) {
387 changed_multi = true;
388 }
389 }
390 return changed_multi;
391}
392
393bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
394{
397
399 return ED_pose_deselect_all_multi_ex(bases, select_mode, ignore_visibility);
400}
401
402/* ***************** Selections ********************** */
403
404static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
405{
406 /* stop when unconnected child is encountered, or when unselectable bone is encountered */
407 if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE)) {
408 return;
409 }
410
411 if (extend) {
412 bone->flag &= ~BONE_SELECTED;
413 }
414 else {
415 bone->flag |= BONE_SELECTED;
416 }
417
418 LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) {
419 selectconnected_posebonechildren(ob, curBone, extend);
420 }
421}
422
423/* within active object context */
424/* previously known as "selectconnected_posearmature" */
426 wmOperator *op,
427 const wmEvent *event)
428{
429 Bone *bone, *curBone, *next = nullptr;
430 const bool extend = RNA_boolean_get(op->ptr, "extend");
431
433
434 Base *base = nullptr;
435 bone = ED_armature_pick_bone(C, event->mval, !extend, &base);
436
437 if (!bone) {
438 return OPERATOR_CANCELLED;
439 }
440
441 /* Select parents */
442 for (curBone = bone; curBone; curBone = next) {
443 /* ignore bone if cannot be selected */
444 if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
445 if (extend) {
446 curBone->flag &= ~BONE_SELECTED;
447 }
448 else {
449 curBone->flag |= BONE_SELECTED;
450 }
451
452 if (curBone->flag & BONE_CONNECTED) {
453 next = curBone->parent;
454 }
455 else {
456 next = nullptr;
457 }
458 }
459 else {
460 next = nullptr;
461 }
462 }
463
464 /* Select children */
465 LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) {
466 selectconnected_posebonechildren(base->object, curBone, extend);
467 }
468
470
472
473 return OPERATOR_FINISHED;
474}
475
480
482{
483 PropertyRNA *prop;
484
485 /* identifiers */
486 ot->name = "Select Connected";
487 ot->idname = "POSE_OT_select_linked_pick";
488 ot->description = "Select bones linked by parent/child connections under the mouse cursor";
489
490 /* callbacks */
491 /* leave 'exec' unset */
494
495 /* flags */
497
498 /* props */
499 prop = RNA_def_boolean(ot->srna,
500 "extend",
501 false,
502 "Extend",
503 "Extend selection instead of deselecting everything first");
505}
506
508{
509 Bone *curBone, *next = nullptr;
510
511 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
512 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
513 continue;
514 }
515
516 bArmature *arm = static_cast<bArmature *>(ob->data);
517
518 /* Select parents */
519 for (curBone = pchan->bone; curBone; curBone = next) {
520 if (PBONE_SELECTABLE(arm, curBone)) {
521 curBone->flag |= BONE_SELECTED;
522
523 if (curBone->flag & BONE_CONNECTED) {
524 next = curBone->parent;
525 }
526 else {
527 next = nullptr;
528 }
529 }
530 else {
531 next = nullptr;
532 }
533 }
534
535 /* Select children */
536 LISTBASE_FOREACH (Bone *, curBone, &pchan->bone->childbase) {
537 selectconnected_posebonechildren(ob, curBone, false);
538 }
540 }
542
544
545 return OPERATOR_FINISHED;
546}
547
549{
550 /* identifiers */
551 ot->name = "Select Connected";
552 ot->idname = "POSE_OT_select_linked";
553 ot->description = "Select all bones linked by parent/child connections to the current selection";
554
555 /* callbacks */
557 ot->poll = ED_operator_posemode;
558
559 /* flags */
561}
562
563/* -------------------------------------- */
564
566{
567 int action = RNA_enum_get(op->ptr, "action");
568
569 Scene *scene = CTX_data_scene(C);
570 int multipaint = scene->toolsettings->multipaint;
571
572 if (action == SEL_TOGGLE) {
573 action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
574 }
575
576 Object *ob_prev = nullptr;
577
578 /* Set the flags. */
579 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
580 bArmature *arm = static_cast<bArmature *>(ob->data);
581 pose_do_bone_select(pchan, action);
582
583 if (ob_prev != ob) {
584 /* Weight-paint or mask modifiers need depsgraph updates. */
585 if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
587 }
588 /* need to tag armature for cow updates, or else selection doesn't update */
590 ob_prev = ob;
591 }
592 }
594
596
598
599 return OPERATOR_FINISHED;
600}
601
603{
604 /* identifiers */
605 ot->name = "(De)select All";
606 ot->idname = "POSE_OT_select_all";
607 ot->description = "Toggle selection status of all bones";
608
609 /* API callbacks. */
611 ot->poll = ED_operator_posemode;
612
613 /* flags */
615
617}
618
619/* -------------------------------------- */
620
622{
624 bArmature *arm = static_cast<bArmature *>(ob->data);
625 bPoseChannel *pchan, *parent;
626
627 /* Determine if there is an active bone */
629 if (pchan) {
630 parent = pchan->parent;
631 if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
632 parent->bone->flag |= BONE_SELECTED;
633 arm->act_bone = parent->bone;
634 }
635 else {
636 return OPERATOR_CANCELLED;
637 }
638 }
639 else {
640 return OPERATOR_CANCELLED;
641 }
642
644
646 return OPERATOR_FINISHED;
647}
648
650{
651 /* identifiers */
652 ot->name = "Select Parent Bone";
653 ot->idname = "POSE_OT_select_parent";
654 ot->description = "Select bones that are parents of the currently selected bones";
655
656 /* API callbacks. */
658 ot->poll = ED_operator_posemode;
659
660 /* flags */
662}
663
664/* -------------------------------------- */
665
667{
668 bool found = false;
669
670 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
671 if (pchan->bone->flag & BONE_SELECTED) {
672 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
673 ListBase targets = {nullptr, nullptr};
674 if (BKE_constraint_targets_get(con, &targets)) {
675 LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
676 Object *ob = ct->tar;
677
678 /* Any armature that is also in pose mode should be selected. */
679 if ((ct->subtarget[0] != '\0') && (ob != nullptr) && (ob->type == OB_ARMATURE) &&
680 (ob->mode == OB_MODE_POSE))
681 {
682 bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
683 if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
686 found = true;
687 }
688 }
689 }
690
691 BKE_constraint_targets_flush(con, &targets, true);
692 }
693 }
694 }
695 }
697
698 if (!found) {
699 return OPERATOR_CANCELLED;
700 }
701
703
704 return OPERATOR_FINISHED;
705}
706
708{
709 /* identifiers */
710 ot->name = "Select Constraint Target";
711 ot->idname = "POSE_OT_select_constraint_target";
712 ot->description = "Select bones used as targets for the currently selected bones";
713
714 /* API callbacks. */
716 ot->poll = ED_operator_posemode;
717
718 /* flags */
720}
721
722/* -------------------------------------- */
723
724/* No need to convert to multi-objects. Just like we keep the non-active bones
725 * selected we then keep the non-active objects untouched (selected/unselected). */
727{
729 bArmature *arm = static_cast<bArmature *>(ob->data);
730 bPoseChannel *pchan_act;
731 int direction = RNA_enum_get(op->ptr, "direction");
732 const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
733 bool changed = false;
734
736 if (pchan_act == nullptr) {
737 return OPERATOR_CANCELLED;
738 }
739
740 if (direction == BONE_SELECT_PARENT) {
741 if (pchan_act->parent) {
742 Bone *bone_parent;
743 bone_parent = pchan_act->parent->bone;
744
745 if (PBONE_SELECTABLE(arm, bone_parent)) {
746 if (!add_to_sel) {
747 pchan_act->bone->flag &= ~BONE_SELECTED;
748 }
749 bone_parent->flag |= BONE_SELECTED;
750 arm->act_bone = bone_parent;
751
752 changed = true;
753 }
754 }
755 }
756 else { /* direction == BONE_SELECT_CHILD */
757 Bone *bone_child = nullptr;
758 int pass;
759
760 /* first pass, only connected bones (the logical direct child) */
761 for (pass = 0; pass < 2 && (bone_child == nullptr); pass++) {
762 LISTBASE_FOREACH (bPoseChannel *, pchan_iter, &ob->pose->chanbase) {
763 /* possible we have multiple children, some invisible */
764 if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
765 if (pchan_iter->parent == pchan_act) {
766 if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
767 bone_child = pchan_iter->bone;
768 break;
769 }
770 }
771 }
772 }
773 }
774
775 if (bone_child) {
776 arm->act_bone = bone_child;
777
778 if (!add_to_sel) {
779 pchan_act->bone->flag &= ~BONE_SELECTED;
780 }
781 bone_child->flag |= BONE_SELECTED;
782
783 changed = true;
784 }
785 }
786
787 if (changed == false) {
788 return OPERATOR_CANCELLED;
789 }
790
792
794
795 return OPERATOR_FINISHED;
796}
797
799{
800 static const EnumPropertyItem direction_items[] = {
801 {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
802 {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
803 {0, nullptr, 0, nullptr, nullptr},
804 };
805
806 /* identifiers */
807 ot->name = "Select Hierarchy";
808 ot->idname = "POSE_OT_select_hierarchy";
809 ot->description = "Select immediate parent/children of selected bones";
810
811 /* API callbacks. */
813 ot->poll = ED_operator_posemode;
814
815 /* flags */
817
818 /* props */
819 ot->prop = RNA_def_enum(
820 ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
821 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
822}
823
824/* -------------------------------------- */
825
826/* Modes for the `select_grouped` operator. */
836
837static bool pose_select_same_color(bContext *C, const bool extend)
838{
839 /* Get a set of all the colors of the selected bones. */
841 blender::Set<Object *> updated_objects;
842 bool changed_any_selection = false;
843
844 /* Old approach that we may want to reinstate behind some option at some point. This will match
845 * against the colors of all selected bones, instead of just the active one. It also explains why
846 * there is a set of colors to begin with.
847 *
848 * CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) {
849 * auto color = blender::animrig::ANIM_bonecolor_posebone_get(pchan);
850 * used_colors.add(color);
851 * }
852 * CTX_DATA_END;
853 */
854 if (!extend) {
855 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
856 pchan->bone->flag &= ~BONE_SELECTED;
857 updated_objects.add(ob);
858 changed_any_selection = true;
859 }
861 }
862
863 /* Use the color of the active pose bone. */
864 bPoseChannel *active_pose_bone = CTX_data_active_pose_bone(C);
865 auto color = blender::animrig::ANIM_bonecolor_posebone_get(active_pose_bone);
866 used_colors.add(color);
867
868 /* Select all visible bones that have the same color. */
869 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
870 Bone *bone = pchan->bone;
871 if (bone->flag & (BONE_UNSELECTABLE | BONE_SELECTED)) {
872 /* Skip bones that are unselectable or already selected. */
873 continue;
874 }
875
877 if (!used_colors.contains(color)) {
878 continue;
879 }
880
881 bone->flag |= BONE_SELECTED;
882 changed_any_selection = true;
883 updated_objects.add(ob);
884 }
886
887 if (!changed_any_selection) {
888 return false;
889 }
890
891 for (Object *ob : updated_objects) {
893 }
894 return true;
895}
896
897static bool pose_select_same_collection(bContext *C, const bool extend)
898{
899 bool changed_any_selection = false;
900 blender::Set<Object *> updated_objects;
901
902 /* Refuse to do anything if there is no active pose bone. */
904 if (!active_pchan) {
905 return false;
906 }
907
908 if (!extend) {
909 /* Deselect all the bones. */
910 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
911 pchan->bone->flag &= ~BONE_SELECTED;
912 updated_objects.add(ob);
913 changed_any_selection = true;
914 }
916 }
917
918 /* Build a set of bone collection names, to allow cross-Armature selection. */
919 blender::Set<std::string> collection_names;
920 LISTBASE_FOREACH (BoneCollectionReference *, bcoll_ref, &active_pchan->bone->runtime.collections)
921 {
922 collection_names.add(bcoll_ref->bcoll->name);
923 }
924
925 /* Select all bones that match any of the collection names. */
926 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
927 Bone *bone = pchan->bone;
928 if (bone->flag & (BONE_UNSELECTABLE | BONE_SELECTED)) {
929 continue;
930 }
931
933 if (!collection_names.contains(bcoll_ref->bcoll->name)) {
934 continue;
935 }
936
937 bone->flag |= BONE_SELECTED;
938 changed_any_selection = true;
939 updated_objects.add(ob);
940 }
941 }
943
944 for (Object *ob : updated_objects) {
946 }
947
948 return changed_any_selection;
949}
950
951/* Useful to get the selection before modifying it. */
953{
954 blender::Set<bPoseChannel *> selected_pose_bones;
955 bArmature *arm = static_cast<bArmature *>((pose_object) ? pose_object->data : nullptr);
956 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
957 if (PBONE_SELECTED(arm, pchan->bone)) {
958 selected_pose_bones.add(pchan);
959 }
960 }
961 return selected_pose_bones;
962}
963
965 const blender::Set<bPoseChannel *> &potential_parents)
966{
967 bPoseChannel *bone_iter = &bone;
968 while (bone_iter) {
969 if (potential_parents.contains(bone_iter)) {
970 return true;
971 }
972 bone_iter = bone_iter->parent;
973 }
974 return false;
975}
976
978{
979 for (bPoseChannel *pose_bone : pose_bones) {
980 if (!pose_bone) {
981 /* There may be a nullptr in the set if selecting siblings of root bones. */
982 continue;
983 }
984 pose_bone->bone->flag &= ~BONE_SELECTED;
985 }
986}
987
988/* Selects children of currently selected bones in all objects in pose mode. If `all` is true, a
989 * bone will be selected if any bone in it's parent hierarchy is selected. If false, only bones
990 * whose direct parent is selected are changed. */
991static bool pose_select_children(bContext *C, const bool all, const bool extend)
992{
995
996 bool changed_any_selection = false;
997
998 for (Object *pose_object : objects) {
999 bArmature *arm = static_cast<bArmature *>(pose_object->data);
1000 BLI_assert(arm);
1001 blender::Set<bPoseChannel *> selected_pose_bones = get_selected_pose_bones(pose_object);
1002 if (!extend) {
1003 deselect_pose_bones(selected_pose_bones);
1004 }
1005 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1006 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1007 continue;
1008 }
1009 if (all) {
1010 if (pose_bone_is_below_one_of(*pchan, selected_pose_bones)) {
1012 changed_any_selection = true;
1013 }
1014 }
1015 else {
1016 if (selected_pose_bones.contains(pchan->parent)) {
1018 changed_any_selection = true;
1019 }
1020 }
1021 }
1022 ED_pose_bone_select_tag_update(pose_object);
1023 }
1024
1025 return changed_any_selection;
1026}
1027
1028static bool pose_select_parents(bContext *C, const bool extend)
1029{
1032
1033 bool changed_any_selection = false;
1034 for (Object *pose_object : objects) {
1035 bArmature *arm = static_cast<bArmature *>(pose_object->data);
1036 BLI_assert(arm);
1037 blender::Set<bPoseChannel *> selected_pose_bones = get_selected_pose_bones(pose_object);
1038 if (!extend) {
1039 deselect_pose_bones(selected_pose_bones);
1040 }
1041 for (bPoseChannel *pchan : selected_pose_bones) {
1042 if (!pchan->parent) {
1043 continue;
1044 }
1045 if (!PBONE_SELECTABLE(arm, pchan->parent->bone)) {
1046 continue;
1047 }
1048 pose_do_bone_select(pchan->parent, SEL_SELECT);
1049 changed_any_selection = true;
1050 }
1051 ED_pose_bone_select_tag_update(pose_object);
1052 }
1053 return changed_any_selection;
1054}
1055
1056static bool pose_select_siblings(bContext *C, const bool extend)
1057{
1060
1061 bool changed_any_selection = false;
1062 for (Object *pose_object : objects) {
1063 bArmature *arm = static_cast<bArmature *>(pose_object->data);
1064 BLI_assert(arm);
1065 blender::Set<bPoseChannel *> parents_of_selected;
1066 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1067 if (PBONE_SELECTED(arm, pchan->bone)) {
1068 parents_of_selected.add(pchan->parent);
1069 }
1070 }
1071 if (!extend) {
1072 deselect_pose_bones(parents_of_selected);
1073 }
1074 LISTBASE_FOREACH (bPoseChannel *, pchan, &pose_object->pose->chanbase) {
1075 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1076 continue;
1077 }
1078 /* Checking if the bone is already selected so `changed_any_selection` stays true to its
1079 * word. */
1080 if (parents_of_selected.contains(pchan->parent) && !PBONE_SELECTED(arm, pchan->bone)) {
1082 changed_any_selection = true;
1083 }
1084 }
1085 ED_pose_bone_select_tag_update(pose_object);
1086 }
1087 return changed_any_selection;
1088}
1089
1091{
1092 using namespace blender::animrig;
1093 Scene *scene = CTX_data_scene(C);
1094 ViewLayer *view_layer = CTX_data_view_layer(C);
1095 bool changed_multi = false;
1097
1098 /* sanity checks: validate Keying Set and object */
1099 if (ks == nullptr) {
1100 BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
1101 return false;
1102 }
1103 if (validate_keyingset(C, nullptr, ks) != ModifyKeyReturn::SUCCESS) {
1104 if (ks->paths.first == nullptr) {
1105 if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1107 RPT_ERROR,
1108 "Use another Keying Set, as the active one depends on the currently "
1109 "selected items or cannot find any targets due to unsuitable context");
1110 }
1111 else {
1112 BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
1113 }
1114 }
1115 return false;
1116 }
1117
1118 /* if not extending selection, deselect all selected first */
1119 if (extend == false) {
1120 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
1121 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
1122 pchan->bone->flag &= ~BONE_SELECTED;
1123 }
1124 }
1126 }
1127
1129
1130 for (const int ob_index : objects.index_range()) {
1131 Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
1132 bArmature *arm = static_cast<bArmature *>((ob) ? ob->data : nullptr);
1133 bPose *pose = (ob) ? ob->pose : nullptr;
1134 bool changed = false;
1135
1136 /* Sanity checks. */
1137 if (ELEM(nullptr, ob, pose, arm)) {
1138 continue;
1139 }
1140
1141 /* iterate over elements in the Keying Set, setting selection depending on whether
1142 * that bone is visible or not...
1143 */
1144 LISTBASE_FOREACH (KS_Path *, ksp, &ks->paths) {
1145 /* only items related to this object will be relevant */
1146 if ((ksp->id == &ob->id) && (ksp->rna_path != nullptr)) {
1147 bPoseChannel *pchan = nullptr;
1148 char boneName[sizeof(pchan->name)];
1149 if (!BLI_str_quoted_substr(ksp->rna_path, "bones[", boneName, sizeof(boneName))) {
1150 continue;
1151 }
1152 pchan = BKE_pose_channel_find_name(pose, boneName);
1153
1154 if (pchan) {
1155 /* select if bone is visible and can be affected */
1156 if (PBONE_SELECTABLE(arm, pchan->bone)) {
1157 pchan->bone->flag |= BONE_SELECTED;
1158 changed = true;
1159 }
1160 }
1161 }
1162 }
1163
1164 if (changed || !extend) {
1166 changed_multi = true;
1167 }
1168 }
1169
1170 return changed_multi;
1171}
1172
1174{
1176 const SelectRelatedMode mode = SelectRelatedMode(RNA_enum_get(op->ptr, "type"));
1177 const bool extend = RNA_boolean_get(op->ptr, "extend");
1178 bool changed = false;
1179
1180 /* sanity check */
1181 if (ob->pose == nullptr) {
1182 return OPERATOR_CANCELLED;
1183 }
1184
1185 /* selection types */
1186 switch (mode) {
1188 changed = pose_select_same_collection(C, extend);
1189 break;
1190
1192 changed = pose_select_same_color(C, extend);
1193 break;
1194
1196 changed = pose_select_same_keyingset(C, op->reports, extend);
1197 break;
1198
1200 changed = pose_select_children(C, true, extend);
1201 break;
1202
1204 changed = pose_select_children(C, false, extend);
1205 break;
1206
1208 changed = pose_select_parents(C, extend);
1209 break;
1210
1212 changed = pose_select_siblings(C, extend);
1213 break;
1214
1215 default:
1216 printf("pose_select_grouped() - Unknown selection type %d\n", int(mode));
1217 break;
1218 }
1219
1220 /* report done status */
1221 if (changed) {
1223
1224 return OPERATOR_FINISHED;
1225 }
1226 return OPERATOR_CANCELLED;
1227}
1228
1230{
1231 static const EnumPropertyItem prop_select_grouped_types[] = {
1233 "COLLECTION",
1234 0,
1235 "Collection",
1236 "Same collections as the active bone"},
1237 {int(SelectRelatedMode::SAME_COLOR), "COLOR", 0, "Color", "Same color as the active bone"},
1239 "KEYINGSET",
1240 0,
1241 "Keying Set",
1242 "All bones affected by active Keying Set"},
1244 "CHILDREN",
1245 0,
1246 "Children",
1247 "Select all children of currently selected bones"},
1249 "CHILDREN_IMMEDIATE",
1250 0,
1251 "Immediate Children",
1252 "Select direct children of currently selected bones"},
1254 "PARENT",
1255 0,
1256 "Parents",
1257 "Select the parents of currently selected bones"},
1259 "SIBILINGS",
1260 0,
1261 "Siblings",
1262 "Select all bones that have the same parent as currently selected bones"},
1263 {0, nullptr, 0, nullptr, nullptr},
1264 };
1265
1266 /* identifiers */
1267 ot->name = "Select Grouped";
1268 ot->description = "Select all visible bones grouped by similar properties";
1269 ot->idname = "POSE_OT_select_grouped";
1270
1271 /* API callbacks. */
1272 ot->invoke = WM_menu_invoke;
1274 ot->poll = ED_operator_posemode; /* TODO: expand to support edit mode as well. */
1275
1276 /* flags */
1277 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1278
1279 /* properties */
1280 RNA_def_boolean(ot->srna,
1281 "extend",
1282 false,
1283 "Extend",
1284 "Extend selection instead of deselecting everything first");
1285 ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
1286}
1287
1288/* -------------------------------------- */
1289
1290/* Add the given selection flags to the bone flags. */
1291static void bone_selection_flags_add(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
1292{
1293 pchan->bone->flag |= (new_selection_flags & BONE_SELECTED);
1294}
1295
1296/* Set the bone flags to the given selection flags. */
1297static void bone_selection_flags_set(bPoseChannel *pchan, const eBone_Flag new_selection_flags)
1298{
1300 pchan->bone->flag |= (new_selection_flags & BONE_SELECTED);
1301}
1302
1307{
1308 const Scene *scene = CTX_data_scene(C);
1309 ViewLayer *view_layer = CTX_data_view_layer(C);
1310 Object *ob_active = CTX_data_active_object(C);
1311
1312 const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
1313 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
1314 const bool extend = RNA_boolean_get(op->ptr, "extend");
1315
1316 const auto set_bone_selection_flags = extend ? bone_selection_flags_add :
1318
1320 for (Object *ob : objects) {
1321 bArmature *arm = static_cast<bArmature *>(ob->data);
1322 bPoseChannel *pchan_mirror_act = nullptr;
1323
1324 /* Remember the pre-mirroring selection flags of the bones. */
1325 blender::Map<bPoseChannel *, eBone_Flag> old_selection_flags;
1326 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1327 /* Treat invisible bones as deselected. */
1328 const int flags = blender::animrig::bone_is_visible_pchan(arm, pchan) ? pchan->bone->flag :
1329 0;
1330
1331 old_selection_flags.add_new(pchan, eBone_Flag(flags));
1332 }
1333
1334 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1335 if (!PBONE_SELECTABLE(arm, pchan->bone)) {
1336 continue;
1337 }
1338
1339 bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
1340 if (!pchan_mirror) {
1341 /* If a bone cannot be mirrored, keep its flags as-is. This makes it possible to select
1342 * the spine and an arm, and still flip the selection to the other arm (without losing
1343 * the selection on the spine). */
1344 continue;
1345 }
1346
1347 if (pchan->bone == arm->act_bone) {
1348 pchan_mirror_act = pchan_mirror;
1349 }
1350
1351 /* If active-only, don't touch unrelated bones. */
1352 if (active_only && !ELEM(arm->act_bone, pchan->bone, pchan_mirror->bone)) {
1353 continue;
1354 }
1355
1356 const eBone_Flag flags_mirror = old_selection_flags.lookup(pchan_mirror);
1357 set_bone_selection_flags(pchan, flags_mirror);
1358 }
1359
1360 if (pchan_mirror_act) {
1361 arm->act_bone = pchan_mirror_act->bone;
1362
1363 /* In weight-paint we select the associated vertex group too. */
1364 if (is_weight_paint) {
1365 blender::ed::object::vgroup_select_by_name(ob_active, pchan_mirror_act->name);
1367 }
1368 }
1369
1371
1372 /* Need to tag armature for cow updates, or else selection doesn't update. */
1374 }
1375
1377
1378 return OPERATOR_FINISHED;
1379}
1380
1382{
1383 /* identifiers */
1384 ot->name = "Select Mirror";
1385 ot->idname = "POSE_OT_select_mirror";
1386 ot->description = "Mirror the bone selection";
1387
1388 /* API callbacks. */
1390 ot->poll = ED_operator_posemode;
1391
1392 /* flags */
1393 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1394
1395 /* properties */
1397 ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
1398 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
1399}
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
ReportList * reports
Definition WM_types.hh:1025
#define ND_BONE_SELECT
Definition WM_types.hh:457
#define NC_OBJECT
Definition WM_types.hh:376
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
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:4226
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)