Blender V4.5
outliner_select.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10
11#include "DNA_armature_types.h"
14#include "DNA_modifier_types.h"
15#include "DNA_object_types.h"
16#include "DNA_scene_types.h"
17#include "DNA_sequence_types.h"
18#include "DNA_shader_fx_types.h"
19
20#include "BLI_listbase.h"
21#include "BLI_utildefines.h"
22
23#include "BKE_armature.hh"
24#include "BKE_collection.hh"
25#include "BKE_constraint.h"
26#include "BKE_context.hh"
27#include "BKE_deform.hh"
28#include "BKE_gpencil_legacy.h"
29#include "BKE_grease_pencil.hh"
30#include "BKE_layer.hh"
31#include "BKE_lib_id.hh"
32#include "BKE_main.hh"
33#include "BKE_modifier.hh"
34#include "BKE_object.hh"
35#include "BKE_particle.h"
36#include "BKE_report.hh"
37#include "BKE_shader_fx.h"
38
39#include "DEG_depsgraph.hh"
41
42#include "ED_armature.hh"
43#include "ED_buttons.hh"
44#include "ED_object.hh"
45#include "ED_outliner.hh"
46#include "ED_screen.hh"
47#include "ED_select_utils.hh"
48#include "ED_sequencer.hh"
49#include "ED_text.hh"
50#include "ED_undo.hh"
51
52#include "SEQ_select.hh"
53#include "SEQ_sequencer.hh"
54
55#include "WM_api.hh"
56#include "WM_message.hh"
57#include "WM_types.hh"
58
59#include "UI_interface.hh"
60#include "UI_view2d.hh"
61
62#include "RNA_access.hh"
63#include "RNA_define.hh"
64#include "RNA_prototypes.hh"
65
66#include "ANIM_armature.hh"
68
69#include "outliner_intern.hh"
72#include "tree/tree_iterator.hh"
73
74namespace blender::ed::outliner {
75
76/* -------------------------------------------------------------------- */
79
86{
87 Main *bmain = CTX_data_main(C);
88 Object *ob = base->object;
89
90 bool changed = false;
92 changed = object::editmode_exit_ex(bmain, scene, ob, object::EM_FREEDATA);
93 if (changed) {
96 }
97 }
98 else {
100 if (changed) {
103 }
104 }
105
106 if (changed) {
109 ED_undo_push(C, "Outliner Edit Mode Toggle");
110 }
111}
112
119{
120 Main *bmain = CTX_data_main(C);
121 Object *ob = base->object;
122
123 if (!BKE_id_is_editable(CTX_data_main(C), &ob->id)) {
124 BKE_report(CTX_wm_reports(C), RPT_WARNING, "Cannot pose non-editable data");
125 return;
126 }
127
128 bool changed = false;
129 if (ob->mode & OB_MODE_POSE) {
130 changed = ED_object_posemode_exit_ex(bmain, ob);
131 if (changed) {
134 }
135 }
136 else {
137 changed = ED_object_posemode_enter_ex(bmain, ob);
138 if (changed) {
141 }
142 }
143
144 if (changed) {
147 ED_undo_push(C, "Outliner Pose Mode Toggle");
148 }
149}
150
163 const TreeViewContext &tvc,
164 Base *base)
165{
166 const eObjectMode active_mode = (eObjectMode)tvc.obact->mode;
168
171 Base *base_active = BKE_view_layer_base_find(tvc.view_layer, tvc.obact);
172 if (base_active != base) {
176 ED_undo_push(C, "Change Active");
177
178 /* Operator call does undo push. */
179 object::mode_set(C, active_mode);
181 }
182 }
184}
185
187 const TreeViewContext &tvc,
188 TreeElement *te,
189 const bool do_extend)
190{
191 TreeStoreElem *tselem = TREESTORE(te);
192
193 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
194 Object *ob = (Object *)tselem->id;
197
198 /* Hidden objects can be removed from the mode. */
199 if (!base || (!(base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) &&
200 (ob->mode != tvc.obact->mode)))
201 {
202 return;
203 }
204
205 if (!do_extend) {
207 }
208 else if (tvc.ob_edit && OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
210 }
211 else if (tvc.ob_pose && ob->type == OB_ARMATURE) {
213 }
214 }
215}
216
218
219/* -------------------------------------------------------------------- */
222
224{
225 /* paranoia check */
226 if (te->store_elem->type != TSE_R_LAYER) {
227 return;
228 }
229
230 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
231 wmWindow *win = CTX_wm_window(C);
232 Scene *scene = WM_window_get_active_scene(win);
233
234 if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
235 WM_window_set_active_view_layer(win, view_layer);
237 }
238}
239
244 ViewLayer *view_layer,
245 Object *ob_parent,
246 bool select)
247{
248 BKE_view_layer_synced_ensure(scene, view_layer);
250 Object *ob = base->object;
251 if (((base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) != 0) &&
252 BKE_object_is_child_recursive(ob_parent, ob))
253 {
255 }
256 }
257}
258
259static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
260{
261 LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
262 if (select && PBONE_SELECTABLE(arm, bone)) {
263 bone->flag |= BONE_SELECTED;
264 }
265 else {
266 bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
267 }
269 }
270}
271
272static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select)
273{
274 EditBone *ebone;
275 for (ebone = ebone_parent->next; ebone; ebone = ebone->next) {
276 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
277 if (select && EBONE_SELECTABLE(arm, ebone)) {
279 }
280 else {
282 }
283 }
284 }
285}
286
288 Scene *scene,
289 ViewLayer *view_layer,
290 TreeElement *te,
291 const eOLSetState set,
292 bool recursive)
293{
294 TreeStoreElem *tselem = TREESTORE(te);
295 TreeStoreElem *parent_tselem = nullptr;
296 TreeElement *parent_te = nullptr;
297 Scene *sce;
298 Base *base;
299 Object *ob = nullptr;
300
301 /* if id is not object, we search back */
302 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
303 ob = (Object *)tselem->id;
304 }
305 else {
306 parent_te = outliner_search_back_te(te, ID_OB);
307 if (parent_te) {
308 parent_tselem = TREESTORE(parent_te);
309 ob = (Object *)parent_tselem->id;
310
311 /* Don't return when activating children of the previous active object. */
312 BKE_view_layer_synced_ensure(scene, view_layer);
313 if (ob == BKE_view_layer_active_object_get(view_layer) && set == OL_SETSEL_NONE) {
314 return;
315 }
316 }
317 }
318 if (ob == nullptr) {
319 return;
320 }
321
322 sce = (Scene *)outliner_search_back(te, ID_SCE);
323 if (sce && scene != sce) {
326 scene = sce;
327 }
328
329 /* find associated base in current scene */
330 BKE_view_layer_synced_ensure(scene, view_layer);
331 base = BKE_view_layer_base_find(view_layer, ob);
332
334 if (base != nullptr) {
335 Object *obact = BKE_view_layer_active_object_get(view_layer);
336 const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
337 if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
338 if (object_mode == OB_MODE_OBJECT) {
339 Main *bmain = CTX_data_main(C);
341 object::mode_generic_exit(bmain, depsgraph, scene, base->object);
342 }
343 if (!BKE_object_is_mode_compat(base->object, object_mode)) {
344 base = nullptr;
345 }
346 }
347 }
348 }
349
350 if (base) {
351 if (set == OL_SETSEL_EXTEND) {
352 /* swap select */
353 if (base->flag & BASE_SELECTED) {
355 if (parent_tselem) {
356 parent_tselem->flag &= ~TSE_SELECTED;
357 }
358 }
359 else {
361 if (parent_tselem) {
362 parent_tselem->flag |= TSE_SELECTED;
363 }
364 }
365 }
366 else if (recursive) {
367 /* Pass */
368 }
369 else {
370 /* De-select all. */
371
372 /* Only in object mode so we can switch the active object,
373 * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
374 * This keeps the convention that all objects in the current mode are also selected.
375 * see #55246. */
377 (ob->mode == OB_MODE_OBJECT) :
378 true)
379 {
380 BKE_view_layer_base_deselect_all(scene, view_layer);
381 }
383 if (parent_tselem) {
384 parent_tselem->flag |= TSE_SELECTED;
385 }
386 }
387
388 if (recursive) {
389 /* Recursive select/deselect for Object hierarchies */
391 scene, view_layer, ob, (base->flag & BASE_SELECTED) != 0);
392 }
393
394 if (set != OL_SETSEL_NONE) {
395 if (!recursive) {
396 object::base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */
397 }
400 }
401 }
402}
403
405 const Scene *scene,
406 ViewLayer *view_layer,
407 TreeElement *te)
408{
409 /* we search for the object parent */
411 /* NOTE: `ob->matbits` can be nullptr when a local object points to a library mesh. */
412 BKE_view_layer_synced_ensure(scene, view_layer);
413 if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
414 ob->matbits == nullptr)
415 {
416 return; /* just paranoia */
417 }
418
419 /* In ob mat array? */
420 TreeElement *tes = te->parent;
421 if (tes->idcode == ID_OB) {
422 ob->actcol = te->index + 1;
423 ob->matbits[te->index] = 1; /* Make ob material active too. */
424 }
425 else {
426 /* or in obdata material */
427 ob->actcol = te->index + 1;
428 ob->matbits[te->index] = 0; /* Make obdata material active too. */
429 }
430
431 /* Tagging object for update seems a bit stupid here, but looks like we have to do it
432 * for render views to update. See #42973.
433 * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
436}
437
439{
441
442 scene->camera = ob;
443
444 Main *bmain = CTX_data_main(C);
445 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
446
447 WM_windows_scene_data_sync(&wm->windows, scene);
451}
452
454{
455 Scene *sce = nullptr;
456
457 TreeElement *tep = te->parent;
458 if (tep) {
459 TreeStoreElem *tselem = TREESTORE(tep);
460 if (tselem->type == TSE_SOME_ID) {
461 sce = (Scene *)tselem->id;
462 }
463 }
464
465 /* make new scene active */
466 if (sce && scene != sce) {
468 }
469}
470
472{
473 /* id in tselem is object */
474 Object *ob = (Object *)tselem->id;
475 BLI_assert(te->index + 1 >= 0);
477
480}
481
483{
484 bGPdata *gpd = (bGPdata *)tselem->id;
485 bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
486
487 /* We can only have a single "active" layer at a time
488 * and there must always be an active layer... */
489 if (gpl) {
493 }
494}
495
497 TreeElement *te,
498 TreeStoreElem *tselem)
499{
500 GreasePencil &grease_pencil = *(GreasePencil *)tselem->id;
502
503 if (node.is_layer()) {
504 if (grease_pencil.has_active_group()) {
506 &grease_pencil.id,
507 &grease_pencil,
508 GreasePencilv3LayerGroup,
509 active);
510 }
512 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
513 }
514 if (node.is_group()) {
515 if (grease_pencil.has_active_layer()) {
517 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
518 }
520 &grease_pencil.id,
521 &grease_pencil,
522 GreasePencilv3LayerGroup,
523 active);
524 }
525
526 grease_pencil.set_active_node(&node);
527
528 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
530}
531
533 TreeElement *te,
534 TreeStoreElem *tselem)
535{
536 bArmature *arm = reinterpret_cast<bArmature *>(tselem->id);
537 BoneCollection *bcoll = reinterpret_cast<BoneCollection *>(te->directdata);
540}
541
543 const Scene *scene,
544 ViewLayer *view_layer,
545 TreeElement *te,
546 TreeStoreElem *tselem,
547 const eOLSetState set,
548 bool recursive)
549{
550 Object *ob = (Object *)tselem->id;
551 bArmature *arm = static_cast<bArmature *>(ob->data);
552 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
553
554 if (set != OL_SETSEL_EXTEND) {
555 /* Single select forces all other bones to get unselected. */
556 const Vector<Object *> objects = BKE_object_pose_array_get_unique(scene, view_layer, nullptr);
557
558 for (Object *ob : objects) {
560
561 /* Sanity checks. */
562 if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) {
563 continue;
564 }
565
566 LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) {
567 pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
568 }
569
570 if (ob != ob_iter) {
571 DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
572 }
573 }
574 }
575
576 if ((set == OL_SETSEL_EXTEND) && (pchan->bone->flag & BONE_SELECTED)) {
577 pchan->bone->flag &= ~BONE_SELECTED;
578 }
579 else {
580 if (blender::animrig::bone_is_visible(arm, pchan->bone)) {
581 pchan->bone->flag |= BONE_SELECTED;
582 }
583 arm->act_bone = pchan->bone;
584 }
585
586 if (recursive) {
587 /* Recursive select/deselect */
588 do_outliner_bone_select_recursive(arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0);
589 }
590
593}
594
596 const Scene *scene,
597 ViewLayer *view_layer,
598 TreeElement *te,
599 TreeStoreElem *tselem,
600 const eOLSetState set,
601 bool recursive)
602{
603 bArmature *arm = (bArmature *)tselem->id;
604 Bone *bone = static_cast<Bone *>(te->directdata);
605
606 BKE_view_layer_synced_ensure(scene, view_layer);
608 if (ob) {
609 if (set != OL_SETSEL_EXTEND) {
610 /* single select forces all other bones to get unselected */
611 for (Bone *bone_iter = static_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
612 bone_iter = bone_iter->next)
613 {
614 bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
615 do_outliner_bone_select_recursive(arm, bone_iter, false);
616 }
617 }
618 }
619
620 if (set == OL_SETSEL_EXTEND && (bone->flag & BONE_SELECTED)) {
621 bone->flag &= ~BONE_SELECTED;
622 }
623 else {
624 if (blender::animrig::bone_is_visible(arm, bone) && ((bone->flag & BONE_UNSELECTABLE) == 0)) {
625 bone->flag |= BONE_SELECTED;
626 }
627 arm->act_bone = bone;
628 }
629
630 if (recursive) {
631 /* Recursive select/deselect */
632 do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0);
633 }
634
636}
637
639static void tree_element_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel)
640{
641 if (sel) {
642 arm->act_edbone = ebone;
643 }
644 if (EBONE_SELECTABLE(arm, ebone)) {
646 }
648}
649
651 const Scene *scene,
652 ViewLayer *view_layer,
653 TreeElement *te,
654 TreeStoreElem *tselem,
655 const eOLSetState set,
656 bool recursive)
657{
658 bArmature *arm = (bArmature *)tselem->id;
659 EditBone *ebone = static_cast<EditBone *>(te->directdata);
660
661 if (set == OL_SETSEL_NORMAL) {
662 ObjectsInModeParams ob_params{};
663 ob_params.object_mode = OB_MODE_EDIT;
664 ob_params.no_dup_data = true;
665
667 scene, view_layer, nullptr, &ob_params);
669
670 tree_element_active_ebone__sel(C, arm, ebone, true);
671 }
672 else if (set == OL_SETSEL_EXTEND) {
673 if (!(ebone->flag & BONE_SELECTED)) {
674 tree_element_active_ebone__sel(C, arm, ebone, true);
675 }
676 else {
677 /* entirely selected, so de-select */
678 tree_element_active_ebone__sel(C, arm, ebone, false);
679 }
680 }
681
682 if (recursive) {
683 /* Recursive select/deselect */
684 do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0);
685 }
686}
687
689 TreeElement *te,
690 TreeStoreElem *tselem,
691 const eOLSetState set)
692{
693 Object *ob = (Object *)tselem->id;
695
696 if (set == OL_SETSEL_NORMAL) {
699 }
700}
701
703{
704 Object *ob = (Object *)tselem->id;
705
707}
708
710 const Scene *scene,
711 ViewLayer *view_layer,
712 TreeElement *te,
713 TreeStoreElem *tselem,
714 const eOLSetState set)
715{
716 Object *ob = (Object *)tselem->id;
717
718 /* Activate the parent bone if this is a bone constraint. */
719 te = te->parent;
720 while (te) {
721 tselem = TREESTORE(te);
722 if (tselem->type == TSE_POSE_CHANNEL) {
723 tree_element_posechannel_activate(C, scene, view_layer, te, tselem, set, false);
724 return;
725 }
726 te = te->parent;
727 }
728
730}
731
733 Scene *scene,
734 TreeElement *te,
735 const eOLSetState set)
736{
738 Strip *strip = &te_strip->get_strip();
739 Editing *ed = seq::editing_get(scene);
740
741 if (BLI_findindex(ed->seqbasep, strip) != -1) {
742 if (set == OL_SETSEL_EXTEND) {
743 seq::select_active_set(scene, nullptr);
744 }
746
747 if ((set == OL_SETSEL_EXTEND) && strip->flag & SELECT) {
748 strip->flag &= ~SELECT;
749 }
750 else {
751 strip->flag |= SELECT;
752 seq::select_active_set(scene, strip);
753 }
754 }
755
757}
758
760{
761 Editing *ed = seq::editing_get(scene);
762
763#if 0
764 select_single_seq(strip, 1);
765#endif
766 Strip *p = static_cast<Strip *>(ed->seqbasep->first);
767 while (p) {
768 if ((!p->data) || (!p->data->stripdata) || (p->data->stripdata->filename[0] == '\0')) {
769 p = p->next;
770 continue;
771 }
772
773#if 0
774 if (STREQ(p->strip->stripdata->filename, strip->data->stripdata->filename)) {
775 select_single_seq(p, 0);
776 }
777#endif
778 p = p->next;
779 }
780}
781
783{
784 ViewLayer *view_layer = CTX_data_view_layer(C);
785 LayerCollection *layer_collection = static_cast<LayerCollection *>(
786 view_layer->layer_collections.first);
787 BKE_layer_collection_activate(view_layer, layer_collection);
788 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
789 * when only the active collection changes. */
791}
792
794{
795 Scene *scene = CTX_data_scene(C);
796 LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata);
797 ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
798 BKE_layer_collection_activate(view_layer, layer_collection);
799 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
800 * when only the active collection changes. */
802}
803
809
810/* ---------------------------------------------- */
811
813 const TreeViewContext &tvc,
814 TreeElement *te,
815 const eOLSetState set,
816 const bool handle_all_types)
817{
818 switch (te->idcode) {
822 case ID_OB:
823 if (handle_all_types) {
824 tree_element_object_activate(C, tvc.scene, tvc.view_layer, te, set, false);
825 }
826 break;
827 case ID_MA:
829 break;
830 case ID_WO:
832 break;
833 case ID_CA:
835 break;
836 case ID_TXT:
838 break;
839 }
840}
841
843 const TreeViewContext &tvc,
844 TreeElement *te,
845 TreeStoreElem *tselem,
846 const eOLSetState set,
847 bool recursive)
848{
850 switch (tselem->type) {
851 case TSE_DEFGROUP:
853 break;
854 case TSE_BONE:
855 tree_element_bone_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
856 break;
857 case TSE_EBONE:
858 tree_element_ebone_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
859 break;
860 case TSE_MODIFIER:
861 tree_element_modifier_activate(C, te, tselem, set);
862 break;
863 case TSE_LINKED_OB:
864 tree_element_object_activate(C, tvc.scene, tvc.view_layer, te, set, false);
865 break;
866 case TSE_LINKED_PSYS:
868 break;
869 case TSE_POSE_BASE:
870 return;
871 case TSE_POSE_CHANNEL:
872 tree_element_posechannel_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
873 break;
875 case TSE_CONSTRAINT:
876 tree_element_constraint_activate(C, tvc.scene, tvc.view_layer, te, tselem, set);
877 break;
878 case TSE_R_LAYER:
880 break;
883 break;
884 case TSE_STRIP:
885 tree_element_strip_activate(C, tvc.scene, te, set);
886 break;
887 case TSE_STRIP_DUP:
889 break;
890 case TSE_GP_LAYER:
891 tree_element_gplayer_activate(C, te, tselem);
892 break;
895 break;
898 break;
901 break;
902 }
903}
904
906 ViewLayer *view_layer,
907 const TreeElement *te,
908 const TreeStoreElem *tselem)
909{
910 const Object *ob = (const Object *)tselem->id;
911 BKE_view_layer_synced_ensure(scene, view_layer);
912 if (ob == BKE_view_layer_active_object_get(view_layer)) {
913 if (BKE_object_defgroup_active_index_get(ob) == te->index + 1) {
914 return OL_DRAWSEL_NORMAL;
915 }
916 }
917 return OL_DRAWSEL_NONE;
918}
919
921 ViewLayer *view_layer,
922 const TreeElement *te,
923 const TreeStoreElem *tselem)
924{
925 const bArmature *arm = (const bArmature *)tselem->id;
926 const Bone *bone = static_cast<Bone *>(te->directdata);
927 BKE_view_layer_synced_ensure(scene, view_layer);
928 const Object *ob = BKE_view_layer_active_object_get(view_layer);
929 if (ob && ob->data == arm) {
930 if (bone->flag & BONE_SELECTED) {
931 return OL_DRAWSEL_NORMAL;
932 }
933 }
934 return OL_DRAWSEL_NONE;
935}
936
938{
939 const EditBone *ebone = static_cast<EditBone *>(te->directdata);
940 if (ebone->flag & BONE_SELECTED) {
941 return OL_DRAWSEL_NORMAL;
942 }
943 return OL_DRAWSEL_NONE;
944}
945
947 const TreeStoreElem *tselem)
948{
949 const Object *ob = (const Object *)tselem->id;
950 const ModifierData *md = (const ModifierData *)te->directdata;
951
953}
954
956 const TreeStoreElem *tselem)
957{
958 return (tselem->id == (const ID *)tvc.obact) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
959}
960
962 const ViewLayer *view_layer,
963 const TreeStoreElem *tselem)
964{
965 const Object *ob = (const Object *)tselem->id;
966 /* This will just lookup in a cache, it will not change the arguments. */
967 BKE_view_layer_synced_ensure(scene, (ViewLayer *)view_layer);
968 const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob);
969 if (base == nullptr) {
970 /* Armature not instantiated in current scene (e.g. inside an appended group). */
971 return OL_DRAWSEL_NONE;
972 }
973
974 if (ob->mode & OB_MODE_POSE) {
975 return OL_DRAWSEL_NORMAL;
976 }
977 return OL_DRAWSEL_NONE;
978}
979
981 const TreeElement *te,
982 const TreeStoreElem *tselem)
983{
984 const Object *ob = (const Object *)tselem->id;
985 const bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
986 if (ob == ob_pose && ob->pose) {
987 if (pchan->bone->flag & BONE_SELECTED) {
988 return OL_DRAWSEL_NORMAL;
989 }
990 }
991 return OL_DRAWSEL_NONE;
992}
993
995 const TreeElement *te)
996{
997 const ViewLayer *te_view_layer = static_cast<ViewLayer *>(te->directdata);
998
999 if (view_layer == te_view_layer) {
1000 return OL_DRAWSEL_NORMAL;
1001 }
1002 return OL_DRAWSEL_NONE;
1003}
1004
1006 const TreeStoreElem *tselem)
1007{
1008 const bArmature *arm = reinterpret_cast<const bArmature *>(tselem->id);
1009 const BoneCollection *bcoll = reinterpret_cast<const BoneCollection *>(te->directdata);
1010
1011 if (arm->runtime.active_collection == bcoll) {
1012 return OL_DRAWSEL_ACTIVE;
1013 }
1014 return OL_DRAWSEL_NONE;
1015}
1016
1018{
1020 const Strip *strip = &te_strip->get_strip();
1021 const Editing *ed = scene->ed;
1022
1023 if (ed && ed->act_strip == strip && strip->flag & SELECT) {
1024 return OL_DRAWSEL_NORMAL;
1025 }
1026 return OL_DRAWSEL_NONE;
1027}
1028
1030{
1032 const Strip *strip = &te_dup->get_strip();
1033 if (strip->flag & SELECT) {
1034 return OL_DRAWSEL_NORMAL;
1035 }
1036 return OL_DRAWSEL_NONE;
1037}
1038
1040{
1041 if (((const bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) {
1042 return OL_DRAWSEL_NORMAL;
1043 }
1044 return OL_DRAWSEL_NONE;
1045}
1046
1048{
1049 GreasePencil &grease_pencil = *(GreasePencil *)te->store_elem->id;
1051 if (node.is_layer() && grease_pencil.is_layer_active(&node.as_layer())) {
1052 return OL_DRAWSEL_NORMAL;
1053 }
1054 return OL_DRAWSEL_NONE;
1055}
1056
1058 const ViewLayer *view_layer, const LayerCollection *layer_collection)
1059{
1060 if (layer_collection == view_layer->layer_collections.first) {
1061 return OL_DRAWSEL_NORMAL;
1062 }
1063 return OL_DRAWSEL_NONE;
1064}
1065
1067 const LayerCollection *layer_collection, const TreeElement *te)
1068{
1069 if (layer_collection == te->directdata) {
1070 return OL_DRAWSEL_NORMAL;
1071 }
1072 return OL_DRAWSEL_NONE;
1073}
1074
1076 ViewLayer *view_layer,
1077 const TreeElement *te)
1078{
1079 /* we search for the object parent */
1080 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1081 /* NOTE: `ob->matbits` can be nullptr when a local object points to a library mesh. */
1082 BKE_view_layer_synced_ensure(scene, view_layer);
1083 if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
1084 ob->matbits == nullptr)
1085 {
1086 return OL_DRAWSEL_NONE; /* just paranoia */
1087 }
1088
1089 /* searching in ob mat array? */
1090 const TreeElement *tes = te->parent;
1091 if (tes->idcode == ID_OB) {
1092 if (ob->actcol == te->index + 1) {
1093 if (ob->matbits[te->index]) {
1094 return OL_DRAWSEL_NORMAL;
1095 }
1096 }
1097 }
1098 /* or we search for obdata material */
1099 else {
1100 if (ob->actcol == te->index + 1) {
1101 if (ob->matbits[te->index] == 0) {
1102 return OL_DRAWSEL_NORMAL;
1103 }
1104 }
1105 }
1106 return OL_DRAWSEL_NONE;
1107}
1108
1110 const TreeElement *te,
1111 const TreeStoreElem *tselem)
1112{
1113 if (te->idcode == ID_SCE) {
1114 if (tselem->id == (ID *)tvc.scene) {
1115 return OL_DRAWSEL_NORMAL;
1116 }
1117 }
1118 return OL_DRAWSEL_NONE;
1119}
1120
1122{
1123 const TreeElement *tep = te->parent;
1124 if (tep == nullptr) {
1125 return OL_DRAWSEL_NORMAL;
1126 }
1127
1128 const TreeStoreElem *tselem = TREESTORE(tep);
1129 if (tselem->id == (const ID *)scene) {
1130 return OL_DRAWSEL_NORMAL;
1131 }
1132 return OL_DRAWSEL_NONE;
1133}
1134
1136{
1137 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1138
1139 return (scene->camera == ob) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
1140}
1141
1143 const TreeElement *te,
1144 const TreeStoreElem *tselem)
1145{
1146 switch (te->idcode) {
1147 case ID_SCE:
1148 return tree_element_active_scene_get(tvc, te, tselem);
1149 case ID_OB:
1150 /* Objects are currently handled by the caller in order to also change text color. */
1151 return OL_DRAWSEL_NONE;
1152 break;
1153 case ID_MA:
1155 case ID_WO:
1156 return tree_element_active_world_get(tvc.scene, te);
1157 case ID_CA:
1158 return tree_element_active_camera_get(tvc.scene, te);
1159 }
1160 return OL_DRAWSEL_NONE;
1161}
1162
1164 const TreeElement *te,
1165 const TreeStoreElem *tselem)
1166{
1167 switch (tselem->type) {
1168 case TSE_DEFGROUP:
1169 return tree_element_defgroup_state_get(tvc.scene, tvc.view_layer, te, tselem);
1170 case TSE_BONE:
1171 return tree_element_bone_state_get(tvc.scene, tvc.view_layer, te, tselem);
1172 case TSE_EBONE:
1174 case TSE_MODIFIER:
1175 return tree_element_modifier_state_get(te, tselem);
1177 return OL_DRAWSEL_NONE;
1178 case TSE_LINKED_OB:
1179 return tree_element_object_state_get(tvc, tselem);
1180 case TSE_LINKED_PSYS:
1181 return OL_DRAWSEL_NONE;
1182 case TSE_POSE_BASE:
1183 return tree_element_pose_state_get(tvc.scene, tvc.view_layer, tselem);
1184 case TSE_POSE_CHANNEL:
1185 return tree_element_posechannel_state_get(tvc.ob_pose, te, tselem);
1187 case TSE_CONSTRAINT:
1188 return OL_DRAWSEL_NONE;
1189 case TSE_R_LAYER:
1191 case TSE_STRIP:
1192 return tree_element_strip_state_get(tvc.scene, te);
1193 case TSE_STRIP_DUP:
1195 case TSE_GP_LAYER:
1204 return tree_element_bone_collection_state_get(te, tselem);
1205 }
1206 return OL_DRAWSEL_NONE;
1207}
1208
1210{
1211 TreeStoreElem *tselem;
1212
1213 te = te->parent;
1214 while (te) {
1215 tselem = TREESTORE(te);
1216 if (tselem->type == TSE_POSE_CHANNEL) {
1217 *r_bone_te = te;
1218 return (bPoseChannel *)te->directdata;
1219 }
1220 te = te->parent;
1221 }
1222
1223 return nullptr;
1224}
1225
1227 PointerRNA *ptr,
1228 const int context)
1229{
1230 bScreen *screen = CTX_wm_screen(C);
1231
1232 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1233 if (area->spacetype != SPACE_PROPERTIES) {
1234 continue;
1235 }
1236
1237 SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
1238 if (ED_buttons_should_sync_with_outliner(C, sbuts, area)) {
1239 ED_buttons_set_context(C, sbuts, ptr, context);
1240 }
1241 }
1242}
1243
1245{
1246 PointerRNA ptr = {};
1247 int context = 0;
1248
1249 /* ID Types */
1250 if (tselem->type == TSE_SOME_ID) {
1251 ptr = RNA_id_pointer_create(tselem->id);
1252
1253 switch (te->idcode) {
1254 case ID_SCE:
1255 context = BCONTEXT_SCENE;
1256 break;
1257 case ID_OB:
1258 context = BCONTEXT_OBJECT;
1259 break;
1260 case ID_ME:
1261 case ID_CU_LEGACY:
1262 case ID_MB:
1263 case ID_IM:
1264 case ID_LT:
1265 case ID_LA:
1266 case ID_CA:
1267 case ID_KE:
1268 case ID_SPK:
1269 case ID_AR:
1270 case ID_GD_LEGACY:
1271 case ID_GP:
1272 case ID_LP:
1273 case ID_CV:
1274 case ID_PT:
1275 case ID_VO:
1276 context = BCONTEXT_DATA;
1277 break;
1278 case ID_MA:
1279 context = BCONTEXT_MATERIAL;
1280 break;
1281 case ID_WO:
1282 context = BCONTEXT_WORLD;
1283 break;
1284 }
1285 }
1286 else {
1287 switch (tselem->type) {
1288 case TSE_DEFGROUP_BASE:
1289 case TSE_DEFGROUP:
1290 ptr = RNA_id_pointer_create(tselem->id);
1291 context = BCONTEXT_DATA;
1292 break;
1294 case TSE_CONSTRAINT: {
1295 TreeElement *bone_te = nullptr;
1296 bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
1297
1298 if (pchan) {
1299 ptr = RNA_pointer_create_discrete(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan);
1300 context = BCONTEXT_BONE_CONSTRAINT;
1301 }
1302 else {
1303 ptr = RNA_id_pointer_create(tselem->id);
1304 context = BCONTEXT_CONSTRAINT;
1305 }
1306
1307 /* Expand the selected constraint in the properties editor. */
1308 if (tselem->type != TSE_CONSTRAINT_BASE) {
1310 }
1311 break;
1312 }
1313 case TSE_MODIFIER_BASE:
1314 case TSE_MODIFIER:
1315 ptr = RNA_id_pointer_create(tselem->id);
1316 context = BCONTEXT_MODIFIER;
1317
1318 if (tselem->type != TSE_MODIFIER_BASE) {
1320
1321 switch ((ModifierType)md->type) {
1323 context = BCONTEXT_PARTICLE;
1324 break;
1331 context = BCONTEXT_PHYSICS;
1332 break;
1333 default:
1334 break;
1335 }
1336
1337 if (context == BCONTEXT_MODIFIER) {
1339 }
1340 }
1341 break;
1343 break;
1345 case TSE_GPENCIL_EFFECT:
1346 ptr = RNA_id_pointer_create(tselem->id);
1347 context = BCONTEXT_SHADERFX;
1348
1349 if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
1351 }
1352 break;
1353 case TSE_BONE: {
1354 bArmature *arm = (bArmature *)tselem->id;
1355 Bone *bone = static_cast<Bone *>(te->directdata);
1356
1357 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Bone, bone);
1358 context = BCONTEXT_BONE;
1359 break;
1360 }
1361 case TSE_EBONE: {
1362 bArmature *arm = (bArmature *)tselem->id;
1363 EditBone *ebone = static_cast<EditBone *>(te->directdata);
1364
1365 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_EditBone, ebone);
1366 context = BCONTEXT_BONE;
1367 break;
1368 }
1369 case TSE_POSE_CHANNEL: {
1370 Object *ob = (Object *)tselem->id;
1371 bArmature *arm = static_cast<bArmature *>(ob->data);
1372 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
1373
1374 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_PoseBone, pchan);
1375 context = BCONTEXT_BONE;
1376 break;
1377 }
1378 case TSE_POSE_BASE: {
1379 Object *ob = (Object *)tselem->id;
1380 bArmature *arm = static_cast<bArmature *>(ob->data);
1381
1382 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Armature, arm);
1383 context = BCONTEXT_DATA;
1384 break;
1385 }
1386 case TSE_R_LAYER: {
1387 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
1388
1389 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_ViewLayer, view_layer);
1390 context = BCONTEXT_VIEW_LAYER;
1391 break;
1392 }
1393 case TSE_LINKED_PSYS: {
1394 Object *ob = (Object *)tselem->id;
1395 ParticleSystem *psys = psys_get_current(ob);
1396
1397 ptr = RNA_pointer_create_discrete(&ob->id, &RNA_ParticleSystem, psys);
1398 context = BCONTEXT_PARTICLE;
1399 break;
1400 }
1401 case TSE_GP_LAYER:
1403 ptr = RNA_id_pointer_create(tselem->id);
1404 context = BCONTEXT_DATA;
1405 break;
1407 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Armature, tselem->id);
1408 context = BCONTEXT_DATA;
1409 break;
1411 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_BoneCollection, te->directdata);
1412 context = BCONTEXT_DATA;
1413 break;
1415 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Collection, te->directdata);
1416 context = BCONTEXT_COLLECTION;
1417 break;
1418 }
1419 }
1420
1421 if (ptr.data) {
1423 }
1424}
1425
1426/* ================================================ */
1427
1435 const TreeViewContext &tvc,
1436 SpaceOutliner *space_outliner,
1437 TreeElement *te,
1438 TreeStoreElem *tselem,
1439 const bool extend,
1440 const bool recursive,
1441 const bool do_activate_data)
1442{
1443 /* Always makes active object, except for some specific types. */
1444 if (ELEM(tselem->type,
1445 TSE_STRIP,
1448 TSE_EBONE,
1451 {
1452 /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several
1453 * objects, we do not want to switch out of edit mode (see #48328 for details). */
1454 }
1455 else if (do_activate_data) {
1457 tvc.scene,
1458 tvc.view_layer,
1459 te,
1460 (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND :
1462 recursive && tselem->type == TSE_SOME_ID);
1463 }
1464 else if (recursive && !(space_outliner->flag & SO_SYNC_SELECT)) {
1465 /* Selection of child objects in hierarchy when sync-selection is OFF. */
1466 tree_iterator::all(te->subtree, [&](TreeElement *te) {
1467 TreeStoreElem *tselem = TREESTORE(te);
1468 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1469 tselem->flag |= TSE_SELECTED;
1470 }
1471 });
1472 }
1473
1474 if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */
1475 if (do_activate_data == false) {
1476 /* Only select in outliner. */
1477 }
1478 else if (te->idcode == ID_SCE) {
1479 if (tvc.scene != (Scene *)tselem->id) {
1481 }
1482 }
1483 else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) {
1484 Collection *gr = (Collection *)tselem->id;
1485 BKE_view_layer_synced_ensure(tvc.scene, tvc.view_layer);
1486
1487 if (extend) {
1490 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1491 if (base && (base->flag & BASE_SELECTED)) {
1492 sel = object::BA_DESELECT;
1493 break;
1494 }
1495 }
1497
1499 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1500 if (base) {
1501 object::base_select(base, sel);
1502 }
1503 }
1505 }
1506 else {
1507 BKE_view_layer_base_deselect_all(tvc.scene, tvc.view_layer);
1508
1510 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1511 /* Object may not be in this scene */
1512 if (base != nullptr) {
1513 if ((base->flag & BASE_SELECTED) == 0) {
1515 }
1516 }
1517 }
1519 }
1520
1521 DEG_id_tag_update(&tvc.scene->id, ID_RECALC_SELECT);
1523 }
1524 else { /* Rest of types. */
1525 tree_element_activate(C, tvc, te, OL_SETSEL_NORMAL, false);
1526 }
1527 }
1528 else if (do_activate_data) {
1530 C, tvc, te, tselem, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive);
1531 }
1532}
1533
1535 SpaceOutliner *space_outliner,
1536 TreeElement *te,
1537 const short select_flag)
1538{
1539 TreeStoreElem *tselem = TREESTORE(te);
1540 const bool activate = select_flag & OL_ITEM_ACTIVATE;
1541 const bool extend = select_flag & OL_ITEM_EXTEND;
1542 const bool activate_data = select_flag & OL_ITEM_SELECT_DATA;
1543 const bool recursive = select_flag & OL_ITEM_RECURSIVE;
1544
1545 /* Clear previous active when activating and clear selection when not extending selection */
1546 const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
1547
1548 /* Do not clear the active and select flag when selecting hierarchies. */
1549 if (clear_flag && !recursive) {
1550 outliner_flag_set(*space_outliner, clear_flag, false);
1551 }
1552
1553 if (select_flag & OL_ITEM_SELECT) {
1554 tselem->flag |= TSE_SELECTED;
1555 }
1556 else {
1557 tselem->flag &= ~TSE_SELECTED;
1558 }
1559
1560 if (activate) {
1561 TreeViewContext tvc;
1563
1564 if (!recursive) {
1565 tselem->flag |= TSE_ACTIVE;
1566 }
1567
1569 tvc,
1570 space_outliner,
1571 te,
1572 tselem,
1573 extend,
1574 select_flag & OL_ITEM_RECURSIVE,
1575 activate_data || space_outliner->flag & SO_SYNC_SELECT);
1576 }
1577}
1578
1580{
1581 /* If we're recursing, we need to know the collection of the selected item in order
1582 * to prevent selecting across collection boundaries. (Object hierarchies might cross
1583 * collection boundaries, i.e., children may be in different collections from their
1584 * parents.) */
1585 Collection *parent_collection = nullptr;
1586 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1587 parent_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1588 }
1589 else if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1590 parent_collection = BKE_collection_object_find(CTX_data_main(C),
1592 nullptr,
1593 reinterpret_cast<Object *>(te->store_elem->id));
1594 }
1595 return parent_collection;
1596}
1597
1598static bool can_select_recursive(TreeElement *te, Collection *in_collection)
1599{
1600 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1601 return true;
1602 }
1603
1604 if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1605 /* Only actually select the object if
1606 * 1. We are not restricted to any collection, or
1607 * 2. The object is in fact in the given collection. */
1608 if (!in_collection || BKE_collection_has_object_recursive(
1609 in_collection, reinterpret_cast<Object *>(te->store_elem->id)))
1610 {
1611 return true;
1612 }
1613 }
1614
1615 return false;
1616}
1617
1618static void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
1619{
1620 LISTBASE_FOREACH (TreeElement *, te, lb) {
1621 TreeStoreElem *tselem = TREESTORE(te);
1622 /* Recursive selection only on collections or objects. */
1623 if (can_select_recursive(te, in_collection)) {
1624 tselem->flag = selecting ? (tselem->flag | TSE_SELECTED) : (tselem->flag & ~TSE_SELECTED);
1625 if (tselem->type == TSE_LAYER_COLLECTION) {
1626 /* Restrict sub-tree selections to this collection. This prevents undesirable behavior in
1627 * the edge-case where there is an object which is part of this collection, but which has
1628 * children that are part of another collection. */
1630 &te->subtree, selecting, static_cast<LayerCollection *>(te->directdata)->collection);
1631 }
1632 else {
1633 do_outliner_select_recursive(&te->subtree, selecting, in_collection);
1634 }
1635 }
1636 else {
1637 tselem->flag &= ~TSE_SELECTED;
1638 }
1639 }
1640}
1641
1644 TreeElement *cursor,
1645 bool selecting,
1646 const bool recurse,
1647 Collection *in_collection)
1648{
1649 LISTBASE_FOREACH (TreeElement *, te, lb) {
1650 TreeStoreElem *tselem = TREESTORE(te);
1651
1652 bool can_select = !recurse || can_select_recursive(te, in_collection);
1653
1654 /* Remember if we are selecting before we potentially change the selecting state. */
1655 bool selecting_before = selecting;
1656
1657 /* Set state for selection */
1658 if (ELEM(te, active, cursor)) {
1659 selecting = !selecting;
1660 }
1661
1662 if (can_select && (selecting_before || selecting)) {
1663 tselem->flag |= TSE_SELECTED;
1664 }
1665
1666 /* Don't look inside closed elements, unless we're forcing the recursion all the way down. */
1667 if (!(tselem->flag & TSE_CLOSED) || recurse) {
1668 /* If this tree element is a collection, then it sets
1669 * the precedent for inclusion of its sub-objects. */
1670 Collection *child_collection = in_collection;
1671 if (tselem->type == TSE_LAYER_COLLECTION) {
1672 child_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1673 }
1675 &te->subtree, active, cursor, selecting, recurse, child_collection);
1676 }
1677 }
1678
1679 return selecting;
1680}
1681
1682/* Select a range of items between cursor and active element */
1684 SpaceOutliner *space_outliner,
1685 TreeElement *cursor,
1686 const bool extend,
1687 const bool recurse,
1688 Collection *in_collection)
1689{
1691
1692 /* If no active element exists, activate the element under the cursor */
1693 if (!active) {
1694 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1695 return;
1696 }
1697
1698 TreeStoreElem *tselem = TREESTORE(active);
1699 const bool active_selected = (tselem->flag & TSE_SELECTED);
1700
1701 if (!extend) {
1702 outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1703 }
1704
1705 /* Select active if under cursor */
1706 if (active == cursor) {
1707 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT);
1708 if (recurse) {
1709 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1710 }
1711 return;
1712 }
1713
1714 /* If active is not selected or visible, select and activate the element under the cursor */
1715 if (!active_selected || !outliner_is_element_visible(active)) {
1716 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1717 return;
1718 }
1719
1721 &space_outliner->tree, active, cursor, false, recurse, in_collection);
1722
1723 if (recurse) {
1724 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1725 /* Select children of active tree element. This is required when
1726 * range selecting from bottom to top, see #117224. */
1728 do_outliner_select_recursive(&active->subtree, true, in_collection);
1729 }
1730}
1731
1733 const ARegion *region,
1734 float view_co_x)
1735{
1736 return (view_co_x > region->v2d.cur.xmax - outliner_right_columns_width(space_outliner));
1737}
1738
1739bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
1740{
1741 if (!outliner_shows_mode_column(*space_outliner)) {
1742 return false;
1743 }
1744
1745 return view_mval[0] < UI_UNIT_X;
1746}
1747
1749 SpaceOutliner *space_outliner,
1750 const float view_mval[2])
1751{
1752 const Scene *scene = CTX_data_scene(C);
1753 ViewLayer *view_layer = CTX_data_view_layer(C);
1754 BKE_view_layer_synced_ensure(scene, view_layer);
1755 Object *obact = BKE_view_layer_active_object_get(view_layer);
1756
1757 return outliner_is_co_within_mode_column(space_outliner, view_mval) && obact &&
1758 obact->mode != OB_MODE_OBJECT;
1759}
1760
1767 const int mval[2],
1768 const bool extend,
1769 const bool use_range,
1770 const bool deselect_all,
1771 const bool recurse)
1772{
1773 ARegion *region = CTX_wm_region(C);
1774 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1775 TreeElement *te;
1776 float view_mval[2];
1777 bool changed = false, rebuild_tree = false;
1778
1779 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
1780
1781 if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) {
1782 return OPERATOR_CANCELLED;
1783 }
1784 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
1785 return OPERATOR_CANCELLED;
1786 }
1787
1788 if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
1789 if (deselect_all) {
1790 changed |= outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1791 }
1792 }
1793 /* Don't allow toggle on scene collection */
1794 else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
1796 {
1798 }
1799 else {
1800 /* The row may also contain children, if one is hovered we want this instead of current te. */
1801 bool merged_elements = false;
1802 bool is_over_icon = false;
1804 space_outliner, te, view_mval[0], &merged_elements, &is_over_icon);
1805
1806 /* If the selected icon was an aggregate of multiple elements, run the search popup */
1807 if (merged_elements) {
1808 merged_element_search_menu_invoke(C, te, activate_te);
1809 return OPERATOR_CANCELLED;
1810 }
1811
1812 TreeStoreElem *activate_tselem = TREESTORE(activate_te);
1813
1814 Collection *parent_collection = nullptr;
1815 if (recurse) {
1816 parent_collection = outliner_collection_get_for_recursive(C, activate_te);
1817 }
1818
1819 /* If we're not recursing (not double clicking), and we are extending or range selecting by
1820 * holding CTRL or SHIFT, ignore events when the cursor is over the icon. This disambiguates
1821 * the case where we are recursing *and* holding CTRL or SHIFT in order to extend or range
1822 * select recursively. */
1823 if (!recurse && (extend || use_range) && is_over_icon) {
1824 return OPERATOR_CANCELLED;
1825 }
1826
1827 if (use_range) {
1829 C, space_outliner, activate_te, extend, (recurse && is_over_icon), parent_collection);
1830 }
1831 else {
1832 const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
1833 view_mval[0]);
1834 /* Always select unless already active and selected. */
1835 bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE) ||
1836 !(activate_tselem->flag & TSE_SELECTED);
1837
1838 /* If we're CTRL+double-clicking and the element is already
1839 * selected, skip the activation and go straight to deselection. */
1840 if (extend && recurse && activate_tselem->flag & TSE_SELECTED) {
1841 select = false;
1842 }
1843
1844 const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
1845 (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
1846 (extend ? OL_ITEM_EXTEND : 0);
1847
1848 /* The recurse flag is set when the user double-clicks
1849 * to select everything in a collection or hierarchy. */
1850 if (recurse) {
1851 if (is_over_icon) {
1852 /* Select or deselect object hierarchy recursively. */
1853 outliner_item_select(C, space_outliner, activate_te, select_flag);
1854 do_outliner_select_recursive(&activate_te->subtree, select, parent_collection);
1855 }
1856 else {
1857 /* Double-clicked, but it wasn't on the icon. */
1859 }
1860 }
1861 else {
1862 outliner_item_select(C, space_outliner, activate_te, select_flag);
1863 }
1864
1865 /* Only switch properties editor tabs when icons are selected. */
1866 if (is_over_icon) {
1867 outliner_set_properties_tab(C, activate_te, activate_tselem);
1868 }
1869 }
1870
1871 changed = true;
1872 }
1873
1874 if (!changed) {
1875 return OPERATOR_CANCELLED;
1876 }
1877
1878 if (rebuild_tree) {
1879 ED_region_tag_redraw(region);
1880 }
1881 else {
1883 }
1884
1886
1887 return OPERATOR_FINISHED;
1888}
1889
1890/* Event can enter-key, then it opens/closes. */
1892 wmOperator *op,
1893 const wmEvent *event)
1894{
1895 ARegion *region = CTX_wm_region(C);
1896
1897 const bool extend = RNA_boolean_get(op->ptr, "extend");
1898 const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
1899 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
1900 const bool recurse = RNA_boolean_get(op->ptr, "recurse");
1901
1902 int mval[2];
1903 WM_event_drag_start_mval(event, region, mval);
1904 return outliner_item_do_activate_from_cursor(C, mval, extend, use_range, deselect_all, recurse);
1905}
1906
1908{
1909 ot->name = "Select";
1910 ot->idname = "OUTLINER_OT_item_activate";
1911 ot->description = "Handle mouse clicks to select and activate items";
1912
1914
1916
1917 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1918
1919 PropertyRNA *prop;
1920 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
1922 prop = RNA_def_boolean(
1923 ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
1925
1926 prop = RNA_def_boolean(ot->srna,
1927 "deselect_all",
1928 false,
1929 "Deselect On Nothing",
1930 "Deselect all when nothing under the cursor");
1932
1933 prop = RNA_def_boolean(
1934 ot->srna, "recurse", false, "Recurse", "Select objects recursively from active element");
1936}
1937
1939
1940/* -------------------------------------------------------------------- */
1943
1945 SpaceOutliner *space_outliner,
1946 const rctf *rectf,
1947 const bool select)
1948{
1949 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1950 if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
1952 C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
1953 }
1954 });
1955}
1956
1958{
1959 Scene *scene = CTX_data_scene(C);
1960 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1961 ARegion *region = CTX_wm_region(C);
1962 rctf rectf;
1963
1964 const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
1965 const bool select = (sel_op != SEL_OP_SUB);
1966 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1967 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1968 }
1969
1971 UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
1972
1973 outliner_box_select(C, space_outliner, &rectf, select);
1974
1978
1980
1981 return OPERATOR_FINISHED;
1982}
1983
1985 wmOperator *op,
1986 const wmEvent *event)
1987{
1988 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1989 ARegion *region = CTX_wm_region(C);
1990 float view_mval[2];
1991 const bool tweak = RNA_boolean_get(op->ptr, "tweak");
1992
1993 int mval[2];
1994 WM_event_drag_start_mval(event, region, mval);
1995 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
1996
1997 /* Find element clicked on */
1998 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
1999
2000 /* Pass through if click is over name or icons, or not tweak event */
2001 if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
2003 }
2004
2005 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
2007 }
2008
2009 return WM_gesture_box_invoke(C, op, event);
2010}
2011
2013{
2014 /* identifiers */
2015 ot->name = "Box Select";
2016 ot->idname = "OUTLINER_OT_select_box";
2017 ot->description = "Use box selection to select tree elements";
2018
2019 /* API callbacks. */
2022 ot->modal = WM_gesture_box_modal;
2023 ot->cancel = WM_gesture_box_cancel;
2024
2026
2027 /* flags */
2028 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2029
2030 /* properties */
2031 PropertyRNA *prop;
2032
2033 prop = RNA_def_boolean(
2034 ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
2036
2039}
2040
2042
2043/* -------------------------------------------------------------------- */
2046
2047/* Given a tree element return the rightmost child that is visible in the outliner */
2049 TreeElement *te)
2050{
2051 while (te->subtree.last) {
2052 if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
2053 te = static_cast<TreeElement *>(te->subtree.last);
2054 }
2055 else {
2056 break;
2057 }
2058 }
2059 return te;
2060}
2061
2062/* Find previous visible element in the tree. */
2064{
2065 if (te->prev) {
2066 te = outliner_find_rightmost_visible_child(space_outliner, te->prev);
2067 }
2068 else if (te->parent) {
2069 /* Use parent if at beginning of list */
2070 te = te->parent;
2071 }
2072
2073 return te;
2074}
2075
2076/* Recursively search up the tree until a successor to a given element is found */
2078{
2079 TreeElement *successor = te;
2080 while (successor->parent) {
2081 if (successor->parent->next) {
2082 te = successor->parent->next;
2083 break;
2084 }
2085 successor = successor->parent;
2086 }
2087
2088 return te;
2089}
2090
2091/* Find next visible element in the tree */
2093{
2094 TreeStoreElem *tselem = TREESTORE(te);
2095
2096 if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
2097 te = static_cast<TreeElement *>(te->subtree.first);
2098 }
2099 else if (te->next) {
2100 te = te->next;
2101 }
2102 else {
2104 }
2105
2106 return te;
2107}
2108
2110 TreeElement *te,
2111 bool toggle_all)
2112{
2113 TreeStoreElem *tselem = TREESTORE(te);
2114
2115 if (TSELEM_OPEN(tselem, space_outliner)) {
2116 outliner_item_openclose(te, false, toggle_all);
2117 }
2118 /* Only walk up a level if the element is closed and not toggling expand */
2119 else if (!toggle_all && te->parent) {
2120 te = te->parent;
2121 }
2122
2123 return te;
2124}
2125
2127 TreeElement *te,
2128 bool toggle_all)
2129{
2130 TreeStoreElem *tselem = TREESTORE(te);
2131
2132 /* Only walk down a level if the element is open and not toggling expand */
2133 if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
2134 te = static_cast<TreeElement *>(te->subtree.first);
2135 }
2136 else {
2137 outliner_item_openclose(te, true, toggle_all);
2138 }
2139
2140 return te;
2141}
2142
2144 TreeElement *te,
2145 const int direction,
2146 const bool extend,
2147 const bool toggle_all)
2148{
2149 TreeStoreElem *tselem = TREESTORE(te);
2150
2151 switch (direction) {
2152 case UI_SELECT_WALK_UP:
2153 te = outliner_find_previous_element(space_outliner, te);
2154 break;
2156 te = outliner_find_next_element(space_outliner, te);
2157 break;
2159 te = outliner_walk_left(space_outliner, te, toggle_all);
2160 break;
2162 te = outliner_walk_right(space_outliner, te, toggle_all);
2163 break;
2164 }
2165
2166 /* If new element is already selected, deselect the previous element */
2167 TreeStoreElem *tselem_new = TREESTORE(te);
2168 if (extend) {
2169 tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
2170 (tselem->flag | TSE_SELECTED);
2171 }
2172
2173 return te;
2174}
2175
2176/* Find the active element to walk from, or set one if none exists.
2177 * Changed is set to true if the active element is found, or false if it was set */
2178static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner, bool *r_changed)
2179{
2180 TreeElement *active_te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
2181 *r_changed = false;
2182
2183 /* If no active element exists, use the first element in the tree */
2184 if (!active_te) {
2185 active_te = static_cast<TreeElement *>(space_outliner->tree.first);
2186 *r_changed = true;
2187 }
2188
2189 /* If the active element is not visible, activate the first visible parent element */
2190 if (!outliner_is_element_visible(active_te)) {
2191 while (!outliner_is_element_visible(active_te)) {
2192 active_te = active_te->parent;
2193 }
2194 *r_changed = true;
2195 }
2196
2197 return active_te;
2198}
2199
2200/* Scroll the outliner when the walk element reaches the top or bottom boundary */
2201static void outliner_walk_scroll(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te)
2202{
2203 /* Account for the header height */
2204 int y_max = region->v2d.cur.ymax - UI_UNIT_Y;
2205 int y_min = region->v2d.cur.ymin;
2206
2207 /* Scroll if walked position is beyond the border */
2208 if (te->ys > y_max) {
2209 outliner_scroll_view(space_outliner, region, te->ys - y_max);
2210 }
2211 else if (te->ys < y_min) {
2212 outliner_scroll_view(space_outliner, region, -(y_min - te->ys));
2213 }
2214}
2215
2217 wmOperator *op,
2218 const wmEvent * /*event*/)
2219{
2220 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2221 ARegion *region = CTX_wm_region(C);
2222
2223 const short direction = RNA_enum_get(op->ptr, "direction");
2224 const bool extend = RNA_boolean_get(op->ptr, "extend");
2225 const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
2226
2227 bool changed;
2228 TreeElement *active_te = find_walk_select_start_element(space_outliner, &changed);
2229
2230 /* If finding the active element did not modify the selection, proceed to walk */
2231 if (!changed) {
2232 active_te = do_outliner_select_walk(space_outliner, active_te, direction, extend, toggle_all);
2233 }
2234
2236 space_outliner,
2237 active_te,
2239
2240 /* Scroll outliner to focus on walk element */
2241 outliner_walk_scroll(space_outliner, region, active_te);
2242
2245
2246 return OPERATOR_FINISHED;
2247}
2248
2250{
2251 /* identifiers */
2252 ot->name = "Walk Select";
2253 ot->idname = "OUTLINER_OT_select_walk";
2254 ot->description = "Use walk navigation to select tree elements";
2255
2256 /* API callbacks. */
2259
2260 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2261
2262 /* properties */
2263 PropertyRNA *prop;
2265 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
2267 prop = RNA_def_boolean(
2268 ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
2270}
2271
2273
2274} // namespace blender::ed::outliner
Functions to deal with Armatures.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
#define PBONE_SELECTABLE(arm, bone)
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
Collection * BKE_collection_object_find(Main *bmain, Scene *scene, Collection *collection, Object *ob)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
void BKE_constraint_panel_expand(struct bConstraint *con)
ReportList * CTX_wm_reports(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
support for deformation groups and hooks.
void BKE_object_defgroup_active_index_set(Object *ob, int new_index)
Definition deform.cc:601
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:596
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Low-level operations for grease pencil.
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
void BKE_view_layer_base_select_and_set_active(ViewLayer *view_layer, Base *selbase)
blender::Vector< Base * > BKE_view_layer_array_from_bases_in_mode_params(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, const ObjectsInModeParams *params)
ViewLayer * BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2503
void BKE_modifier_panel_expand(ModifierData *md)
General operations, lookup, etc. for blender objects.
void BKE_object_modifier_set_active(Object *ob, ModifierData *md)
bool BKE_object_is_in_editmode(const Object *ob)
Object * BKE_object_pose_armature_get(Object *ob)
ModifierData * BKE_object_active_modifier(const Object *ob)
bool BKE_object_is_mode_compat(const Object *ob, eObjectMode object_mode)
blender::Vector< Object * > BKE_object_pose_array_get_unique(const Scene *scene, ViewLayer *view_layer, View3D *v3d)
bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_child)
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition particle.cc:537
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx)
Definition shader_fx.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define ELEM(...)
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ 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
@ ID_CA
@ ID_AR
@ ID_IM
@ ID_VO
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SCE
@ ID_CV
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_ME
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PT
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_TIPSEL
struct Collection Collection
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
struct Base Base
@ eModifierType_ParticleSystem
@ eModifierType_Fluidsim
@ eModifierType_Cloth
@ eModifierType_Fluid
@ eModifierType_Collision
@ eModifierType_DynamicPaint
@ eModifierType_Softbody
eObjectMode
@ OB_MODE_EDIT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define OB_TYPE_SUPPORT_EDITMODE(_type)
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_ACTIVE
@ TSE_STRIP_DUP
@ TSE_BONE_COLLECTION
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_STRIP
@ TSE_MODIFIER_BASE
@ TSE_GP_LAYER
@ TSE_GPENCIL_EFFECT
@ TSE_LINKED_NODE_TREE
@ TSE_STRIP_DATA
@ TSE_VIEW_COLLECTION_BASE
@ TSE_EBONE
@ TSE_BONE
@ TSE_LINKED_PSYS
@ TSE_DEFGROUP_BASE
@ TSE_CONSTRAINT
@ TSE_LAYER_COLLECTION
@ TSE_GREASE_PENCIL_NODE
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_LINKED_OB
@ TSE_SOME_ID
@ TSE_MODIFIER
@ TSE_BONE_COLLECTION_BASE
@ TSE_R_LAYER
@ TSE_POSE_BASE
@ TSE_DEFGROUP
@ SCE_OBJECT_MODE_LOCK
#define BASE_SELECTED(v3d, base)
@ SPACE_PROPERTIES
@ SO_SYNC_SELECT
@ SO_VIEW_LAYER
@ BCONTEXT_CONSTRAINT
@ BCONTEXT_COLLECTION
@ BCONTEXT_VIEW_LAYER
@ BCONTEXT_MATERIAL
@ BCONTEXT_SHADERFX
@ BCONTEXT_MODIFIER
@ BCONTEXT_BONE
@ BCONTEXT_DATA
@ BCONTEXT_OBJECT
@ BCONTEXT_BONE_CONSTRAINT
@ BCONTEXT_PHYSICS
@ BCONTEXT_SCENE
@ BCONTEXT_WORLD
@ BCONTEXT_PARTICLE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
#define EBONE_SELECTABLE(arm, ebone)
void ED_buttons_set_context(const bContext *C, SpaceProperties *sbuts, PointerRNA *ptr, int context)
bool ED_buttons_should_sync_with_outliner(const bContext *C, const SpaceProperties *sbuts, ScrArea *area)
void ED_outliner_select_sync_from_object_tag(bContext *C)
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
bool ED_operator_region_outliner_active(bContext *C)
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:659
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
bool ED_operator_outliner_active(bContext *C)
eSelectOp
@ SEL_OP_SUB
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ UI_SELECT_WALK_RIGHT
@ UI_SELECT_WALK_UP
@ UI_SELECT_WALK_LEFT
@ UI_SELECT_WALK_DOWN
bool ED_text_activate_in_screen(bContext *C, Text *text)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:99
void ED_undo_group_begin(bContext *C)
Definition ed_undo.cc:87
void ED_undo_group_end(bContext *C)
Definition ed_undo.cc:93
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
#define UI_UNIT_X
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1674
#define ND_SEQUENCER
Definition WM_types.hh:434
#define NA_ACTIVATED
Definition WM_types.hh:587
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_SCREEN
Definition WM_types.hh:374
#define ND_MODE
Definition WM_types.hh:442
#define ND_OB_SELECT
Definition WM_types.hh:439
#define NC_SCENE
Definition WM_types.hh:375
#define ND_MODIFIER
Definition WM_types.hh:459
#define NA_EDITED
Definition WM_types.hh:581
#define ND_PARTICLE
Definition WM_types.hh:462
#define NS_MODE_OBJECT
Definition WM_types.hh:557
#define NC_MATERIAL
Definition WM_types.hh:377
#define ND_CONSTRAINT
Definition WM_types.hh:461
#define NC_GPENCIL
Definition WM_types.hh:396
#define ND_BONE_ACTIVE
Definition WM_types.hh:456
#define ND_TRANSFORM
Definition WM_types.hh:453
#define ND_LAYER
Definition WM_types.hh:447
#define ND_BONE_COLLECTION
Definition WM_types.hh:471
#define NS_MODE_POSE
Definition WM_types.hh:566
#define NC_OBJECT
Definition WM_types.hh:376
#define ND_SHADING_LINKS
Definition WM_types.hh:476
#define NS_LAYER_COLLECTION
Definition WM_types.hh:577
#define NA_SELECTED
Definition WM_types.hh:586
bool ED_armature_edit_deselect_all_multi_ex(const Span< Base * > bases)
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child)
void ED_armature_ebone_select_set(EditBone *ebone, bool select)
BPy_StructRNA * depsgraph
void activate(bool forceActivation=false) const
#define SELECT
#define active
#define select(A, B, C)
bool bone_is_visible(const bArmature *armature, const Bone *bone)
void base_select(Base *base, eObjectSelect_Mode mode)
void mode_generic_exit(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
bool editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag)
void base_activate_with_mode_exit_if_needed(bContext *C, Base *base)
bool mode_set(bContext *C, eObjectMode mode)
bool editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
static void do_outliner_object_select_recursive(const Scene *scene, ViewLayer *view_layer, Object *ob_parent, bool select)
static void tree_element_constraint_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner, ARegion *region)
static void tree_element_master_collection_activate(const bContext *C)
static void do_outliner_range_select(bContext *C, SpaceOutliner *space_outliner, TreeElement *cursor, const bool extend, const bool recurse, Collection *in_collection)
static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *te)
static void do_outliner_item_activate_tree_element(bContext *C, const TreeViewContext &tvc, SpaceOutliner *space_outliner, TreeElement *te, TreeStoreElem *tselem, const bool extend, const bool recursive, const bool do_activate_data)
static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select)
static eOLDrawState tree_element_active_camera_get(const Scene *scene, const TreeElement *te)
eOLDrawState tree_element_type_active_state_get(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
static eOLDrawState tree_element_pose_state_get(const Scene *scene, const ViewLayer *view_layer, const TreeStoreElem *tselem)
static wmOperatorStatus outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static eOLDrawState tree_element_bone_collection_state_get(const TreeElement *te, const TreeStoreElem *tselem)
static void tree_element_bone_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
static void outliner_box_select(bContext *C, SpaceOutliner *space_outliner, const rctf *rectf, const bool select)
static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
TreeElement * outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner, TreeElement *parent_te, float view_co_x, bool *r_is_merged_icon, bool *r_is_over_icon)
static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *base)
static eOLDrawState tree_element_viewlayer_state_get(const ViewLayer *view_layer, const TreeElement *te)
static bool outliner_is_co_within_active_mode_column(bContext *C, SpaceOutliner *space_outliner, const float view_mval[2])
static TreeElement * outliner_walk_left(SpaceOutliner *space_outliner, TreeElement *te, bool toggle_all)
static eOLDrawState tree_element_strip_state_get(const Scene *scene, const TreeElement *te)
static void outliner_sync_to_properties_editors(const bContext *C, PointerRNA *ptr, const int context)
float outliner_right_columns_width(const SpaceOutliner *space_outliner)
static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose, const TreeElement *te, const TreeStoreElem *tselem)
static TreeElement * outliner_find_next_element(SpaceOutliner *space_outliner, TreeElement *te)
static eOLDrawState tree_element_ebone_state_get(const TreeElement *te)
static bool do_outliner_range_select_recursive(ListBase *lb, TreeElement *active, TreeElement *cursor, bool selecting, const bool recurse, Collection *in_collection)
static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *base)
static void tree_element_bonecollection_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
TreeElement * outliner_search_back_te(TreeElement *te, short idcode)
static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem)
static Collection * outliner_collection_get_for_recursive(bContext *C, TreeElement *te)
void tree_element_activate(bContext *C, const TreeViewContext &tvc, TreeElement *te, eOLSetState set, bool handle_all_types)
bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
static void tree_element_posechannel_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
void OUTLINER_OT_item_activate(wmOperatorType *ot)
static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te)
static wmOperatorStatus outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
static eOLDrawState tree_element_gplayer_state_get(const TreeElement *te)
bPoseChannel * outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te)
static eOLDrawState tree_element_master_collection_state_get(const ViewLayer *view_layer, const LayerCollection *layer_collection)
static TreeElement * outliner_find_previous_element(SpaceOutliner *space_outliner, TreeElement *te)
static wmOperatorStatus outliner_item_do_activate_from_cursor(bContext *C, const int mval[2], const bool extend, const bool use_range, const bool deselect_all, const bool recurse)
static TreeElement * do_outliner_select_walk(SpaceOutliner *space_outliner, TreeElement *te, const int direction, const bool extend, const bool toggle_all)
static void outliner_walk_scroll(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te)
static TreeElement * outliner_walk_right(SpaceOutliner *space_outliner, TreeElement *te, bool toggle_all)
void outliner_item_mode_toggle(bContext *C, const TreeViewContext &tvc, TreeElement *te, bool do_extend)
void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
void OUTLINER_OT_select_walk(wmOperatorType *ot)
static void tree_element_viewlayer_activate(bContext *C, TreeElement *te)
static eOLDrawState tree_element_active_material_get(const Scene *scene, ViewLayer *view_layer, const TreeElement *te)
static TreeElement * find_walk_select_start_element(SpaceOutliner *space_outliner, bool *r_changed)
void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int delta_y)
static void tree_element_modifier_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set)
bool outliner_is_element_visible(const TreeElement *te)
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
static void tree_element_ebone_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive)
static eOLDrawState tree_element_defgroup_state_get(const Scene *scene, ViewLayer *view_layer, const TreeElement *te, const TreeStoreElem *tselem)
static eOLDrawState tree_element_active_world_get(const Scene *scene, const TreeElement *te)
TreeElementT * tree_element_cast(const TreeElement *te)
ID * outliner_search_back(TreeElement *te, short idcode)
static eOLDrawState tree_element_bone_state_get(const Scene *scene, ViewLayer *view_layer, const TreeElement *te, const TreeStoreElem *tselem)
static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_outliner, const ARegion *region, float view_co_x)
void merged_element_search_menu_invoke(bContext *C, TreeElement *parent_te, TreeElement *activate_te)
static void tree_element_psys_activate(bContext *C, TreeStoreElem *tselem)
static eOLDrawState tree_element_grease_pencil_node_state_get(const TreeElement *te)
static void do_outliner_item_mode_toggle_generic(bContext *C, const TreeViewContext &tvc, Base *base)
static eOLDrawState tree_element_object_state_get(const TreeViewContext &tvc, const TreeStoreElem *tselem)
static void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
static void tree_element_strip_dup_activate(Scene *scene, TreeElement *)
static TreeElement * outliner_find_rightmost_visible_child(SpaceOutliner *space_outliner, TreeElement *te)
static void tree_element_material_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te)
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
TreeElement * outliner_find_element_with_flag(const ListBase *lb, short flag)
static void tree_element_strip_activate(bContext *C, Scene *scene, TreeElement *te, const eOLSetState set)
static void tree_element_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel)
void tree_element_type_active_set(bContext *C, const TreeViewContext &tvc, TreeElement *te, TreeStoreElem *tselem, eOLSetState set, bool recursive)
static wmOperatorStatus outliner_box_select_exec(bContext *C, wmOperator *op)
static TreeElement * outliner_element_find_successor_in_parents(TreeElement *te)
static void tree_element_layer_collection_activate(bContext *C, TreeElement *te)
bool outliner_shows_mode_column(const SpaceOutliner &space_outliner)
eOLDrawState tree_element_active_state_get(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
static wmOperatorStatus outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static eOLDrawState tree_element_modifier_state_get(const TreeElement *te, const TreeStoreElem *tselem)
static eOLDrawState tree_element_layer_collection_state_get(const LayerCollection *layer_collection, const TreeElement *te)
static void tree_element_text_activate(bContext *C, TreeElement *te)
void OUTLINER_OT_select_box(wmOperatorType *ot)
static eOLDrawState tree_element_strip_dup_state_get(const TreeElement *te)
static eOLDrawState tree_element_active_scene_get(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
static bool can_select_recursive(TreeElement *te, Collection *in_collection)
static void tree_element_grease_pencil_node_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
void outliner_item_select(bContext *C, SpaceOutliner *space_outliner, TreeElement *te, short select_flag)
static void tree_element_object_activate(bContext *C, Scene *scene, ViewLayer *view_layer, TreeElement *te, const eOLSetState set, bool recursive)
bool deselect_all_strips(const Scene *scene)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
void select_active_set(Scene *scene, Strip *strip)
#define TREESTORE(a)
#define TSELEM_OPEN(telm, sv)
bool ED_object_posemode_enter_ex(Main *bmain, Object *ob)
Definition pose_edit.cc:77
bool ED_object_posemode_exit_ex(Main *bmain, Object *ob)
Definition pose_edit.cc:112
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
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
struct Bone * next
ListBase childbase
EditBone * next
Definition DNA_ID.h:404
struct Collection * collection
void * last
void * first
ListBase wm
Definition BKE_main.hh:276
struct bPose * pose
char * matbits
struct ToolSettings * toolsettings
struct Editing * ed
ListBase view_layers
struct Object * camera
StripElem * stripdata
char filename[256]
StripData * data
struct Strip * next
ListBase layer_collections
struct BoneCollection * active_collection
struct EditBone * act_edbone
struct bArmature_Runtime runtime
struct Bone * bone
ListBase chanbase
ListBase areabase
float xmax
float ymax
float ymin
struct PointerRNA * ptr
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(wmOperator *op, rctf *r_rect)
void WM_operator_properties_select_walk_direction(wmOperatorType *ot)
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)