Blender V5.0
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->flag |= POSE_SELECTED;
68 }
69 break;
70 case SEL_DESELECT:
71 pchan->flag &= ~POSE_SELECTED;
72 break;
73 case SEL_INVERT:
74 if (pchan->flag & POSE_SELECTED) {
75 pchan->flag &= ~POSE_SELECTED;
76 }
77 else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
78 pchan->flag |= POSE_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 (blender::animrig::bone_is_selectable(arm, pchan)) {
113 /* change selection state - activate too if selected */
114 if (select) {
115 pchan->flag |= POSE_SELECTED;
116 if (change_active) {
117 arm->act_bone = pchan->bone;
118 }
119 }
120 else {
121 pchan->flag &= ~POSE_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 bPoseChannel *pchan,
138{
139 bool found = false;
140 bool changed = false;
141
142 if (ob->pose) {
143 if (pchan && pchan->bone && ((pchan->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) && (pchan->flag & POSE_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 pchan->flag &= ~POSE_SELECTED;
189 }
190 }
191
192 switch (params.sel_op) {
193 case SEL_OP_ADD: {
194 pchan->flag |= POSE_SELECTED;
195 arm->act_bone = pchan->bone;
196 break;
197 }
198 case SEL_OP_SUB: {
199 pchan->flag &= ~POSE_SELECTED;
200 break;
201 }
202 case SEL_OP_XOR: {
203 if (pchan->flag & POSE_SELECTED) {
204 /* If not active, we make it active. */
205 if (pchan->bone != arm->act_bone) {
206 arm->act_bone = pchan->bone;
207 }
208 else {
209 pchan->flag &= ~POSE_SELECTED;
210 }
211 }
212 else {
213 pchan->flag |= POSE_SELECTED;
214 arm->act_bone = pchan->bone;
215 }
216 break;
217 }
218 case SEL_OP_SET: {
219 pchan->flag |= POSE_SELECTED;
220 arm->act_bone = pchan->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 (pchan->bone && pchan->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 bPoseChannel *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(arm, pchan)) {
324 if (pchan->flag & POSE_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(arm, pchan)) {
337 int flag_prev = pchan->flag;
338 pose_do_bone_select(pchan, select_mode);
339 changed = (changed || flag_prev != pchan->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(arm, pchan)) {
350 if (pchan->flag & POSE_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
401 bPoseChannel &pose_bone,
402 const bool extend)
403{
405 *ob.pose, pose_bone, [extend](bPoseChannel &child) {
406 if (!child.bone) {
407 BLI_assert_unreachable();
408 return false;
409 }
410 /* Stop when unconnected child is encountered, or when unselectable bone is encountered. */
411 if (!(child.bone->flag & BONE_CONNECTED) || (child.bone->flag & BONE_UNSELECTABLE)) {
412 return false;
413 }
414
415 if (extend) {
416 child.flag &= ~POSE_SELECTED;
417 }
418 else {
419 child.flag |= POSE_SELECTED;
420 }
421 return true;
422 });
423}
424
425/* within active object context */
426/* previously known as "selectconnected_posearmature" */
428 wmOperator *op,
429 const wmEvent *event)
430{
431 bPoseChannel *pchan, *curBone, *next = nullptr;
432 const bool extend = RNA_boolean_get(op->ptr, "extend");
433
435
436 Base *base = nullptr;
437 pchan = ED_armature_pick_pchan(C, event->mval, !extend, &base);
438
439 if (!pchan) {
440 return OPERATOR_CANCELLED;
441 }
442
443 /* Select parents */
444 for (curBone = pchan; curBone; curBone = next) {
445 /* ignore bone if cannot be selected */
446 if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
447 if (extend) {
448 curBone->flag &= ~POSE_SELECTED;
449 }
450 else {
451 curBone->flag |= POSE_SELECTED;
452 }
453
454 if (curBone->bone->flag & BONE_CONNECTED) {
455 next = curBone->parent;
456 }
457 else {
458 next = nullptr;
459 }
460 }
461 else {
462 next = nullptr;
463 }
464 }
465
466 /* Select children */
467 selectconnected_posebonechildren(*base->object, *pchan, extend);
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 bPoseChannel *curBone, *next = nullptr;
510
511 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
512 if ((pchan->flag & POSE_SELECTED) == 0) {
513 continue;
514 }
515
516 bArmature *arm = static_cast<bArmature *>(ob->data);
517
518 /* Select parents */
519 for (curBone = pchan; curBone; curBone = next) {
520 if (blender::animrig::bone_is_selectable(arm, curBone)) {
521 curBone->flag |= POSE_SELECTED;
522
523 if (curBone->bone->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 selectconnected_posebonechildren(*ob, *pchan, false);
538 }
540
542
543 return OPERATOR_FINISHED;
544}
545
547{
548 /* identifiers */
549 ot->name = "Select Connected";
550 ot->idname = "POSE_OT_select_linked";
551 ot->description = "Select all bones linked by parent/child connections to the current selection";
552
553 /* callbacks */
555 ot->poll = ED_operator_posemode;
556
557 /* flags */
559}
560
561/* -------------------------------------- */
562
564{
565 int action = RNA_enum_get(op->ptr, "action");
566
567 Scene *scene = CTX_data_scene(C);
568 int multipaint = scene->toolsettings->multipaint;
569
570 if (action == SEL_TOGGLE) {
571 action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
572 }
573
574 Object *ob_prev = nullptr;
575
576 /* Set the flags. */
577 CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
578 bArmature *arm = static_cast<bArmature *>(ob->data);
579 pose_do_bone_select(pchan, action);
580
581 if (ob_prev != ob) {
582 /* Weight-paint or mask modifiers need depsgraph updates. */
583 if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
585 }
586 /* need to tag armature for cow updates, or else selection doesn't update */
588 ob_prev = ob;
589 }
590 }
592
594
596
597 return OPERATOR_FINISHED;
598}
599
601{
602 /* identifiers */
603 ot->name = "(De)select All";
604 ot->idname = "POSE_OT_select_all";
605 ot->description = "Toggle selection status of all bones";
606
607 /* API callbacks. */
609 ot->poll = ED_operator_posemode;
610
611 /* flags */
613
615}
616
617/* -------------------------------------- */
618
620{
622 bArmature *arm = static_cast<bArmature *>(ob->data);
623 bPoseChannel *pchan, *parent;
624
625 /* Determine if there is an active bone */
627 if (pchan) {
628 parent = pchan->parent;
629 if ((parent) && !(parent->drawflag & PCHAN_DRAW_HIDDEN) &&
630 !(parent->bone->flag & BONE_UNSELECTABLE))
631 {
632 parent->flag |= POSE_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->flag & POSE_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)) {
684 pchanc->flag |= POSE_SELECTED;
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 (blender::animrig::bone_is_selectable(arm, bone_parent)) {
746 if (!add_to_sel) {
747 pchan_act->flag &= ~POSE_SELECTED;
748 }
749 pchan_act->parent->flag |= POSE_SELECTED;
750 arm->act_bone = bone_parent;
751
752 changed = true;
753 }
754 }
755 }
756 else { /* direction == BONE_SELECT_CHILD */
757 bPoseChannel *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 (blender::animrig::bone_is_selectable(arm, pchan_iter)) {
765 if (pchan_iter->parent == pchan_act) {
766 if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
767 bone_child = pchan_iter;
768 break;
769 }
770 }
771 }
772 }
773 }
774
775 if (bone_child) {
776 arm->act_bone = bone_child->bone;
777
778 if (!add_to_sel) {
779 pchan_act->flag &= ~POSE_SELECTED;
780 }
781 bone_child->flag |= POSE_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->flag &= ~POSE_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) && (pchan->flag & POSE_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 pchan->flag |= POSE_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->flag &= ~POSE_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 ((pchan->flag & POSE_SELECTED) && bone->flag & BONE_UNSELECTABLE) {
929 continue;
930 }
931
933 if (!collection_names.contains(bcoll_ref->bcoll->name)) {
934 continue;
935 }
936
937 pchan->flag |= POSE_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 (blender::animrig::bone_is_selected(arm, pchan)) {
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->flag &= ~POSE_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 (!blender::animrig::bone_is_selectable(arm, pchan)) {
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 (!blender::animrig::bone_is_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 (blender::animrig::bone_is_selected(arm, pchan)) {
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 (!blender::animrig::bone_is_selectable(arm, pchan)) {
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) &&
1082 {
1084 changed_any_selection = true;
1085 }
1086 }
1087 ED_pose_bone_select_tag_update(pose_object);
1088 }
1089 return changed_any_selection;
1090}
1091
1092static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool extend)
1093{
1094 using namespace blender::animrig;
1095 Scene *scene = CTX_data_scene(C);
1096 ViewLayer *view_layer = CTX_data_view_layer(C);
1097 bool changed_multi = false;
1099
1100 /* sanity checks: validate Keying Set and object */
1101 if (ks == nullptr) {
1102 BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
1103 return false;
1104 }
1105 if (validate_keyingset(C, nullptr, ks) != ModifyKeyReturn::SUCCESS) {
1106 if (ks->paths.first == nullptr) {
1107 if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
1108 BKE_report(reports,
1109 RPT_ERROR,
1110 "Use another Keying Set, as the active one depends on the currently "
1111 "selected items or cannot find any targets due to unsuitable context");
1112 }
1113 else {
1114 BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
1115 }
1116 }
1117 return false;
1118 }
1119
1120 /* if not extending selection, deselect all selected first */
1121 if (extend == false) {
1122 CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
1123 if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
1124 pchan->flag &= ~POSE_SELECTED;
1125 }
1126 }
1128 }
1129
1131
1132 for (const int ob_index : objects.index_range()) {
1133 Object *ob = BKE_object_pose_armature_get(objects[ob_index]);
1134 bArmature *arm = static_cast<bArmature *>((ob) ? ob->data : nullptr);
1135 bPose *pose = (ob) ? ob->pose : nullptr;
1136 bool changed = false;
1137
1138 /* Sanity checks. */
1139 if (ELEM(nullptr, ob, pose, arm)) {
1140 continue;
1141 }
1142
1143 /* iterate over elements in the Keying Set, setting selection depending on whether
1144 * that bone is visible or not...
1145 */
1146 LISTBASE_FOREACH (KS_Path *, ksp, &ks->paths) {
1147 /* only items related to this object will be relevant */
1148 if ((ksp->id == &ob->id) && (ksp->rna_path != nullptr)) {
1149 bPoseChannel *pchan = nullptr;
1150 char boneName[sizeof(pchan->name)];
1151 if (!BLI_str_quoted_substr(ksp->rna_path, "bones[", boneName, sizeof(boneName))) {
1152 continue;
1153 }
1154 pchan = BKE_pose_channel_find_name(pose, boneName);
1155
1156 if (pchan) {
1157 /* select if bone is visible and can be affected */
1158 if (blender::animrig::bone_is_selectable(arm, pchan)) {
1159 pchan->flag |= POSE_SELECTED;
1160 changed = true;
1161 }
1162 }
1163 }
1164 }
1165
1166 if (changed || !extend) {
1168 changed_multi = true;
1169 }
1170 }
1171
1172 return changed_multi;
1173}
1174
1176{
1178 const SelectRelatedMode mode = SelectRelatedMode(RNA_enum_get(op->ptr, "type"));
1179 const bool extend = RNA_boolean_get(op->ptr, "extend");
1180 bool changed = false;
1181
1182 /* sanity check */
1183 if (ob->pose == nullptr) {
1184 return OPERATOR_CANCELLED;
1185 }
1186
1187 /* selection types */
1188 switch (mode) {
1190 changed = pose_select_same_collection(C, extend);
1191 break;
1192
1194 changed = pose_select_same_color(C, extend);
1195 break;
1196
1198 changed = pose_select_same_keyingset(C, op->reports, extend);
1199 break;
1200
1202 changed = pose_select_children(C, true, extend);
1203 break;
1204
1206 changed = pose_select_children(C, false, extend);
1207 break;
1208
1210 changed = pose_select_parents(C, extend);
1211 break;
1212
1214 changed = pose_select_siblings(C, extend);
1215 break;
1216
1217 default:
1218 printf("pose_select_grouped() - Unknown selection type %d\n", int(mode));
1219 break;
1220 }
1221
1222 /* report done status */
1223 if (changed) {
1225
1226 return OPERATOR_FINISHED;
1227 }
1228 return OPERATOR_CANCELLED;
1229}
1230
1232{
1233 static const EnumPropertyItem prop_select_grouped_types[] = {
1235 "COLLECTION",
1236 0,
1237 "Collection",
1238 "Same collections as the active bone"},
1239 {int(SelectRelatedMode::SAME_COLOR), "COLOR", 0, "Color", "Same color as the active bone"},
1241 "KEYINGSET",
1242 0,
1243 "Keying Set",
1244 "All bones affected by active Keying Set"},
1246 "CHILDREN",
1247 0,
1248 "Children",
1249 "Select all children of currently selected bones"},
1251 "CHILDREN_IMMEDIATE",
1252 0,
1253 "Immediate Children",
1254 "Select direct children of currently selected bones"},
1256 "PARENT",
1257 0,
1258 "Parents",
1259 "Select the parents of currently selected bones"},
1261 "SIBLINGS",
1262 0,
1263 "Siblings",
1264 "Select all bones that have the same parent as currently selected bones"},
1265 {0, nullptr, 0, nullptr, nullptr},
1266 };
1267
1268 /* identifiers */
1269 ot->name = "Select Grouped";
1270 ot->description = "Select all visible bones grouped by similar properties";
1271 ot->idname = "POSE_OT_select_grouped";
1272
1273 /* API callbacks. */
1274 ot->invoke = WM_menu_invoke;
1276 ot->poll = ED_operator_posemode; /* TODO: expand to support edit mode as well. */
1277
1278 /* flags */
1279 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1280
1281 /* properties */
1282 RNA_def_boolean(ot->srna,
1283 "extend",
1284 false,
1285 "Extend",
1286 "Extend selection instead of deselecting everything first");
1287 ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
1288}
1289
1290/* -------------------------------------- */
1291
1292/* Add the given selection flags to the bone flags. */
1293static void bone_selection_flags_add(bPoseChannel *pchan, const ePchan_Flag new_selection_flags)
1294{
1295 pchan->flag |= new_selection_flags;
1296}
1297
1298/* Set the bone flags to the given selection flags. */
1299static void bone_selection_flags_set(bPoseChannel *pchan, const ePchan_Flag new_selection_flags)
1300{
1301 pchan->flag = new_selection_flags;
1302}
1303
1308{
1309 const Scene *scene = CTX_data_scene(C);
1310 ViewLayer *view_layer = CTX_data_view_layer(C);
1311 Object *ob_active = CTX_data_active_object(C);
1312
1313 const bool is_weight_paint = (ob_active->mode & OB_MODE_WEIGHT_PAINT) != 0;
1314 const bool active_only = RNA_boolean_get(op->ptr, "only_active");
1315 const bool extend = RNA_boolean_get(op->ptr, "extend");
1316
1317 const auto set_bone_selection_flags = extend ? bone_selection_flags_add :
1319
1321 for (Object *ob : objects) {
1322 bArmature *arm = static_cast<bArmature *>(ob->data);
1323 bPoseChannel *pchan_mirror_act = nullptr;
1324
1325 /* Remember the pre-mirroring selection flags of the bones. */
1327 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1328 /* Treat invisible bones as deselected. */
1329 const int flags = blender::animrig::bone_is_visible(arm, pchan) ? pchan->flag : 0;
1330
1331 old_selection_flags.add_new(pchan, ePchan_Flag(flags));
1332 }
1333
1334 LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
1335 if (!blender::animrig::bone_is_selectable(arm, pchan)) {
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 ePchan_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
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)
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#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:521
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ PCHAN_DRAW_HIDDEN
ePchan_Flag
@ POSE_SELECTED
@ KEYINGSET_ABSOLUTE
@ BONE_UNSELECTABLE
@ 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:344
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_BONE_SELECT
Definition WM_types.hh:460
#define NC_OBJECT
Definition WM_types.hh:379
bPoseChannel * ED_armature_pick_pchan_from_selectbuffer(blender::Span< Base * > bases, const GPUSelectResult *hit_results, int hits, bool findunsel, bool do_nearest, Base **r_base)
bPoseChannel * ED_armature_pick_pchan(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 printf(...)
#define select(A, B, C)
bool all(VecOp< bool, D >) RET
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(const bArmature *armature, const Bone *bone)
bool bone_is_selectable(const bArmature *armature, const bPoseChannel *pchan)
bool bone_is_selected(const bArmature *armature, const Bone *bone)
bool pose_bone_descendent_depth_iterator(bPose &pose, bPoseChannel &pose_bone, FunctionRef< bool(bPoseChannel &child_bone)> callback)
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 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 void selectconnected_posebonechildren(Object &ob, bPoseChannel &pose_bone, const bool extend)
static void bone_selection_flags_set(bPoseChannel *pchan, const ePchan_Flag new_selection_flags)
static void bone_selection_flags_add(bPoseChannel *pchan, const ePchan_Flag new_selection_flags)
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, bPoseChannel *pchan, 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)
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 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
char name[64]
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:763
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:4237
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)