Blender V4.3
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
9#include <cstdlib>
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_armature_types.h"
16#include "DNA_modifier_types.h"
17#include "DNA_object_types.h"
18#include "DNA_scene_types.h"
19#include "DNA_sequence_types.h"
20#include "DNA_shader_fx_types.h"
21
22#include "BLI_listbase.h"
23#include "BLI_utildefines.h"
24
25#include "BKE_armature.hh"
26#include "BKE_collection.hh"
27#include "BKE_constraint.h"
28#include "BKE_context.hh"
29#include "BKE_deform.hh"
30#include "BKE_gpencil_legacy.h"
31#include "BKE_grease_pencil.hh"
32#include "BKE_layer.hh"
33#include "BKE_lib_id.hh"
34#include "BKE_main.hh"
35#include "BKE_modifier.hh"
36#include "BKE_object.hh"
37#include "BKE_particle.h"
38#include "BKE_report.hh"
39#include "BKE_shader_fx.h"
40
41#include "DEG_depsgraph.hh"
43
44#include "ED_armature.hh"
45#include "ED_buttons.hh"
46#include "ED_object.hh"
47#include "ED_outliner.hh"
48#include "ED_screen.hh"
49#include "ED_select_utils.hh"
50#include "ED_sequencer.hh"
51#include "ED_text.hh"
52#include "ED_undo.hh"
53
54#include "SEQ_select.hh"
55#include "SEQ_sequencer.hh"
56
57#include "WM_api.hh"
58#include "WM_message.hh"
59#include "WM_types.hh"
60
61#include "UI_interface.hh"
62#include "UI_view2d.hh"
63
64#include "RNA_access.hh"
65#include "RNA_define.hh"
66#include "RNA_prototypes.hh"
67
69
70#include "outliner_intern.hh"
73#include "tree/tree_iterator.hh"
74
75namespace blender::ed::outliner {
76
77/* -------------------------------------------------------------------- */
87{
88 Main *bmain = CTX_data_main(C);
89 Object *ob = base->object;
90
91 bool changed = false;
93 changed = object::editmode_exit_ex(bmain, scene, ob, object::EM_FREEDATA);
94 if (changed) {
97 }
98 }
99 else {
101 if (changed) {
104 }
105 }
106
107 if (changed) {
110 ED_undo_push(C, "Outliner Edit Mode Toggle");
111 }
112}
113
120{
121 Main *bmain = CTX_data_main(C);
122 Object *ob = base->object;
123
124 if (!BKE_id_is_editable(CTX_data_main(C), &ob->id)) {
125 BKE_report(CTX_wm_reports(C), RPT_WARNING, "Cannot pose non-editable data");
126 return;
127 }
128
129 bool changed = false;
130 if (ob->mode & OB_MODE_POSE) {
131 changed = ED_object_posemode_exit_ex(bmain, ob);
132 if (changed) {
135 }
136 }
137 else {
138 changed = ED_object_posemode_enter_ex(bmain, ob);
139 if (changed) {
142 }
143 }
144
145 if (changed) {
148 ED_undo_push(C, "Outliner Pose Mode Toggle");
149 }
150}
151
164{
165 const eObjectMode active_mode = (eObjectMode)tvc->obact->mode;
167
170 Base *base_active = BKE_view_layer_base_find(tvc->view_layer, tvc->obact);
171 if (base_active != base) {
175 ED_undo_push(C, "Change Active");
176
177 /* Operator call does undo push. */
178 object::mode_set(C, active_mode);
180 }
181 }
183}
184
186 TreeViewContext *tvc,
187 TreeElement *te,
188 const bool do_extend)
189{
190 TreeStoreElem *tselem = TREESTORE(te);
191
192 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
193 Object *ob = (Object *)tselem->id;
195 Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
196
197 /* Hidden objects can be removed from the mode. */
198 if (!base || (!(base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) &&
199 (ob->mode != tvc->obact->mode)))
200 {
201 return;
202 }
203
204 if (!do_extend) {
206 }
207 else if (tvc->ob_edit && OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
209 }
210 else if (tvc->ob_pose && ob->type == OB_ARMATURE) {
212 }
213 }
214}
215
218/* -------------------------------------------------------------------- */
223{
224 /* paranoia check */
225 if (te->store_elem->type != TSE_R_LAYER) {
226 return;
227 }
228
229 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
230 wmWindow *win = CTX_wm_window(C);
231 Scene *scene = WM_window_get_active_scene(win);
232
233 if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
234 WM_window_set_active_view_layer(win, view_layer);
236 }
237}
238
243 ViewLayer *view_layer,
244 Object *ob_parent,
245 bool select)
246{
247 BKE_view_layer_synced_ensure(scene, view_layer);
249 Object *ob = base->object;
250 if (((base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) != 0) &&
251 BKE_object_is_child_recursive(ob_parent, ob))
252 {
254 }
255 }
256}
257
258static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
259{
260 LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
261 if (select && PBONE_SELECTABLE(arm, bone)) {
262 bone->flag |= BONE_SELECTED;
263 }
264 else {
265 bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
266 }
268 }
269}
270
271static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select)
272{
273 EditBone *ebone;
274 for (ebone = ebone_parent->next; ebone; ebone = ebone->next) {
275 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
276 if (select && EBONE_SELECTABLE(arm, ebone)) {
278 }
279 else {
281 }
282 }
283 }
284}
285
287 Scene *scene,
288 ViewLayer *view_layer,
289 TreeElement *te,
290 const eOLSetState set,
291 bool recursive)
292{
293 TreeStoreElem *tselem = TREESTORE(te);
294 TreeStoreElem *parent_tselem = nullptr;
295 TreeElement *parent_te = nullptr;
296 Scene *sce;
297 Base *base;
298 Object *ob = nullptr;
299
300 /* if id is not object, we search back */
301 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
302 ob = (Object *)tselem->id;
303 }
304 else {
305 parent_te = outliner_search_back_te(te, ID_OB);
306 if (parent_te) {
307 parent_tselem = TREESTORE(parent_te);
308 ob = (Object *)parent_tselem->id;
309
310 /* Don't return when activating children of the previous active object. */
311 BKE_view_layer_synced_ensure(scene, view_layer);
312 if (ob == BKE_view_layer_active_object_get(view_layer) && set == OL_SETSEL_NONE) {
313 return;
314 }
315 }
316 }
317 if (ob == nullptr) {
318 return;
319 }
320
321 sce = (Scene *)outliner_search_back(te, ID_SCE);
322 if (sce && scene != sce) {
325 scene = sce;
326 }
327
328 /* find associated base in current scene */
329 BKE_view_layer_synced_ensure(scene, view_layer);
330 base = BKE_view_layer_base_find(view_layer, ob);
331
332 if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
333 if (base != nullptr) {
334 Object *obact = BKE_view_layer_active_object_get(view_layer);
335 const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
336 if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
337 if (object_mode == OB_MODE_OBJECT) {
338 Main *bmain = CTX_data_main(C);
340 object::mode_generic_exit(bmain, depsgraph, scene, base->object);
341 }
342 if (!BKE_object_is_mode_compat(base->object, object_mode)) {
343 base = nullptr;
344 }
345 }
346 }
347 }
348
349 if (base) {
350 if (set == OL_SETSEL_EXTEND) {
351 /* swap select */
352 if (base->flag & BASE_SELECTED) {
354 if (parent_tselem) {
355 parent_tselem->flag &= ~TSE_SELECTED;
356 }
357 }
358 else {
360 if (parent_tselem) {
361 parent_tselem->flag |= TSE_SELECTED;
362 }
363 }
364 }
365 else if (recursive) {
366 /* Pass */
367 }
368 else {
369 /* De-select all. */
370
371 /* Only in object mode so we can switch the active object,
372 * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
373 * This keeps the convention that all objects in the current mode are also selected.
374 * see #55246. */
375 if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ?
376 (ob->mode == OB_MODE_OBJECT) :
377 true)
378 {
379 BKE_view_layer_base_deselect_all(scene, view_layer);
380 }
382 if (parent_tselem) {
383 parent_tselem->flag |= TSE_SELECTED;
384 }
385 }
386
387 if (recursive) {
388 /* Recursive select/deselect for Object hierarchies */
390 scene, view_layer, ob, (base->flag & BASE_SELECTED) != 0);
391 }
392
393 if (set != OL_SETSEL_NONE) {
394 if (!recursive) {
395 object::base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */
396 }
399 }
400 }
401}
402
404 const Scene *scene,
405 ViewLayer *view_layer,
406 TreeElement *te)
407{
408 /* we search for the object parent */
410 /* NOTE: `ob->matbits` can be nullptr when a local object points to a library mesh. */
411 BKE_view_layer_synced_ensure(scene, view_layer);
412 if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
413 ob->matbits == nullptr)
414 {
415 return; /* just paranoia */
416 }
417
418 /* In ob mat array? */
419 TreeElement *tes = te->parent;
420 if (tes->idcode == ID_OB) {
421 ob->actcol = te->index + 1;
422 ob->matbits[te->index] = 1; /* Make ob material active too. */
423 }
424 else {
425 /* or in obdata material */
426 ob->actcol = te->index + 1;
427 ob->matbits[te->index] = 0; /* Make obdata material active too. */
428 }
429
430 /* Tagging object for update seems a bit stupid here, but looks like we have to do it
431 * for render views to update. See #42973.
432 * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
435}
436
438{
440
441 scene->camera = ob;
442
443 Main *bmain = CTX_data_main(C);
444 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
445
450}
451
453{
454 Scene *sce = nullptr;
455
456 TreeElement *tep = te->parent;
457 if (tep) {
458 TreeStoreElem *tselem = TREESTORE(tep);
459 if (tselem->type == TSE_SOME_ID) {
460 sce = (Scene *)tselem->id;
461 }
462 }
463
464 /* make new scene active */
465 if (sce && scene != sce) {
467 }
468}
469
471{
472 /* id in tselem is object */
473 Object *ob = (Object *)tselem->id;
474 BLI_assert(te->index + 1 >= 0);
476
479}
480
482{
483 bGPdata *gpd = (bGPdata *)tselem->id;
484 bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
485
486 /* We can only have a single "active" layer at a time
487 * and there must always be an active layer... */
488 if (gpl) {
492 }
493}
494
496 TreeElement *te,
497 TreeStoreElem *tselem)
498{
499 GreasePencil &grease_pencil = *(GreasePencil *)tselem->id;
501
502 if (node.is_layer()) {
503 if (grease_pencil.has_active_group()) {
505 &grease_pencil.id,
506 &grease_pencil,
507 GreasePencilv3LayerGroup,
508 active);
509 }
511 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
512 }
513 if (node.is_group()) {
514 if (grease_pencil.has_active_layer()) {
516 CTX_wm_message_bus(C), &grease_pencil.id, &grease_pencil, GreasePencilv3Layers, active);
517 }
519 &grease_pencil.id,
520 &grease_pencil,
521 GreasePencilv3LayerGroup,
522 active);
523 }
524
525 grease_pencil.set_active_node(&node);
526
527 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
528 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, &grease_pencil);
529}
530
532 TreeElement *te,
533 TreeStoreElem *tselem)
534{
535 bArmature *arm = reinterpret_cast<bArmature *>(tselem->id);
536 BoneCollection *bcoll = reinterpret_cast<BoneCollection *>(te->directdata);
539}
540
542 const Scene *scene,
543 ViewLayer *view_layer,
544 TreeElement *te,
545 TreeStoreElem *tselem,
546 const eOLSetState set,
547 bool recursive)
548{
549 Object *ob = (Object *)tselem->id;
550 bArmature *arm = static_cast<bArmature *>(ob->data);
551 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
552
553 if (set != OL_SETSEL_EXTEND) {
554 /* Single select forces all other bones to get unselected. */
555 const Vector<Object *> objects = BKE_object_pose_array_get_unique(scene, view_layer, nullptr);
556
557 for (Object *ob : objects) {
559
560 /* Sanity checks. */
561 if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) {
562 continue;
563 }
564
565 LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) {
566 pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
567 }
568
569 if (ob != ob_iter) {
570 DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
571 }
572 }
573 }
574
575 if ((set == OL_SETSEL_EXTEND) && (pchan->bone->flag & BONE_SELECTED)) {
576 pchan->bone->flag &= ~BONE_SELECTED;
577 }
578 else {
579 if (ANIM_bone_is_visible(arm, pchan->bone)) {
580 pchan->bone->flag |= BONE_SELECTED;
581 }
582 arm->act_bone = pchan->bone;
583 }
584
585 if (recursive) {
586 /* Recursive select/deselect */
587 do_outliner_bone_select_recursive(arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0);
588 }
589
592}
593
595 const Scene *scene,
596 ViewLayer *view_layer,
597 TreeElement *te,
598 TreeStoreElem *tselem,
599 const eOLSetState set,
600 bool recursive)
601{
602 bArmature *arm = (bArmature *)tselem->id;
603 Bone *bone = static_cast<Bone *>(te->directdata);
604
605 BKE_view_layer_synced_ensure(scene, view_layer);
607 if (ob) {
608 if (set != OL_SETSEL_EXTEND) {
609 /* single select forces all other bones to get unselected */
610 for (Bone *bone_iter = static_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
611 bone_iter = bone_iter->next)
612 {
613 bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
614 do_outliner_bone_select_recursive(arm, bone_iter, false);
615 }
616 }
617 }
618
619 if (set == OL_SETSEL_EXTEND && (bone->flag & BONE_SELECTED)) {
620 bone->flag &= ~BONE_SELECTED;
621 }
622 else {
623 if (ANIM_bone_is_visible(arm, bone) && ((bone->flag & BONE_UNSELECTABLE) == 0)) {
624 bone->flag |= BONE_SELECTED;
625 }
626 arm->act_bone = bone;
627 }
628
629 if (recursive) {
630 /* Recursive select/deselect */
631 do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0);
632 }
633
635}
636
638static void tree_element_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel)
639{
640 if (sel) {
641 arm->act_edbone = ebone;
642 }
643 if (ANIM_bone_is_visible_editbone(arm, ebone) && ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
645 }
647}
648
650 const Scene *scene,
651 ViewLayer *view_layer,
652 TreeElement *te,
653 TreeStoreElem *tselem,
654 const eOLSetState set,
655 bool recursive)
656{
657 bArmature *arm = (bArmature *)tselem->id;
658 EditBone *ebone = static_cast<EditBone *>(te->directdata);
659
660 if (set == OL_SETSEL_NORMAL) {
661 ObjectsInModeParams ob_params{};
662 ob_params.object_mode = OB_MODE_EDIT;
663 ob_params.no_dup_data = true;
664
666 scene, view_layer, nullptr, &ob_params);
668
669 tree_element_active_ebone__sel(C, arm, ebone, true);
670 }
671 else if (set == OL_SETSEL_EXTEND) {
672 if (!(ebone->flag & BONE_SELECTED)) {
673 tree_element_active_ebone__sel(C, arm, ebone, true);
674 }
675 else {
676 /* entirely selected, so de-select */
677 tree_element_active_ebone__sel(C, arm, ebone, false);
678 }
679 }
680
681 if (recursive) {
682 /* Recursive select/deselect */
683 do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0);
684 }
685}
686
688 TreeElement *te,
689 TreeStoreElem *tselem,
690 const eOLSetState set)
691{
692 Object *ob = (Object *)tselem->id;
694
695 if (set == OL_SETSEL_NORMAL) {
698 }
699}
700
702{
703 Object *ob = (Object *)tselem->id;
704
706}
707
709 const Scene *scene,
710 ViewLayer *view_layer,
711 TreeElement *te,
712 TreeStoreElem *tselem,
713 const eOLSetState set)
714{
715 Object *ob = (Object *)tselem->id;
716
717 /* Activate the parent bone if this is a bone constraint. */
718 te = te->parent;
719 while (te) {
720 tselem = TREESTORE(te);
721 if (tselem->type == TSE_POSE_CHANNEL) {
722 tree_element_posechannel_activate(C, scene, view_layer, te, tselem, set, false);
723 return;
724 }
725 te = te->parent;
726 }
727
729}
730
732 Scene *scene,
733 TreeElement *te,
734 const eOLSetState set)
735{
737 Sequence *seq = &te_seq->get_sequence();
738 Editing *ed = SEQ_editing_get(scene);
739
740 if (BLI_findindex(ed->seqbasep, seq) != -1) {
741 if (set == OL_SETSEL_EXTEND) {
742 SEQ_select_active_set(scene, nullptr);
743 }
745
746 if ((set == OL_SETSEL_EXTEND) && seq->flag & SELECT) {
747 seq->flag &= ~SELECT;
748 }
749 else {
750 seq->flag |= SELECT;
751 SEQ_select_active_set(scene, seq);
752 }
753 }
754
756}
757
759{
760 Editing *ed = SEQ_editing_get(scene);
761
762#if 0
763 select_single_seq(seq, 1);
764#endif
765 Sequence *p = static_cast<Sequence *>(ed->seqbasep->first);
766 while (p) {
767 if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->filename[0] == '\0')) {
768 p = p->next;
769 continue;
770 }
771
772#if 0
773 if (STREQ(p->strip->stripdata->filename, seq->strip->stripdata->filename)) {
774 select_single_seq(p, 0);
775 }
776#endif
777 p = p->next;
778 }
779}
780
782{
783 ViewLayer *view_layer = CTX_data_view_layer(C);
784 LayerCollection *layer_collection = static_cast<LayerCollection *>(
785 view_layer->layer_collections.first);
786 BKE_layer_collection_activate(view_layer, layer_collection);
787 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
788 * when only the active collection changes. */
790}
791
793{
794 Scene *scene = CTX_data_scene(C);
795 LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata);
796 ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
797 BKE_layer_collection_activate(view_layer, layer_collection);
798 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
799 * when only the active collection changes. */
801}
802
804{
805 Text *text = (Text *)te->store_elem->id;
807}
808
809/* ---------------------------------------------- */
810
812 const TreeViewContext *tvc,
813 TreeElement *te,
814 const eOLSetState set,
815 const bool handle_all_types)
816{
817 switch (te->idcode) {
821 case ID_OB:
822 if (handle_all_types) {
823 tree_element_object_activate(C, tvc->scene, tvc->view_layer, te, set, false);
824 }
825 break;
826 case ID_MA:
828 break;
829 case ID_WO:
831 break;
832 case ID_CA:
834 break;
835 case ID_TXT:
837 break;
838 }
839}
840
842 const TreeViewContext *tvc,
843 TreeElement *te,
844 TreeStoreElem *tselem,
845 const eOLSetState set,
846 bool recursive)
847{
849 switch (tselem->type) {
850 case TSE_DEFGROUP:
851 tree_element_defgroup_activate(C, te, tselem);
852 break;
853 case TSE_BONE:
854 tree_element_bone_activate(C, tvc->scene, tvc->view_layer, te, tselem, set, recursive);
855 break;
856 case TSE_EBONE:
857 tree_element_ebone_activate(C, tvc->scene, tvc->view_layer, te, tselem, set, recursive);
858 break;
859 case TSE_MODIFIER:
860 tree_element_modifier_activate(C, te, tselem, set);
861 break;
862 case TSE_LINKED_OB:
863 tree_element_object_activate(C, tvc->scene, tvc->view_layer, te, set, false);
864 break;
865 case TSE_LINKED_PSYS:
867 break;
868 case TSE_POSE_BASE:
869 return;
870 case TSE_POSE_CHANNEL:
872 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_SEQUENCE:
885 tree_element_sequence_activate(C, tvc->scene, te, set);
886 break;
887 case TSE_SEQUENCE_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{
996 /* paranoia check */
997 if (te->idcode != ID_SCE) {
998 return OL_DRAWSEL_NONE;
999 }
1000
1001 const ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
1002
1003 if (CTX_data_view_layer(C) == view_layer) {
1004 return OL_DRAWSEL_NORMAL;
1005 }
1006 return OL_DRAWSEL_NONE;
1007}
1008
1010 const TreeStoreElem *tselem)
1011{
1012 const bArmature *arm = reinterpret_cast<const bArmature *>(tselem->id);
1013 const BoneCollection *bcoll = reinterpret_cast<const BoneCollection *>(te->directdata);
1014
1015 if (arm->runtime.active_collection == bcoll) {
1016 return OL_DRAWSEL_ACTIVE;
1017 }
1018 return OL_DRAWSEL_NONE;
1019}
1020
1022{
1024 const Sequence *seq = &te_seq->get_sequence();
1025 const Editing *ed = scene->ed;
1026
1027 if (ed && ed->act_seq == seq && seq->flag & SELECT) {
1028 return OL_DRAWSEL_NORMAL;
1029 }
1030 return OL_DRAWSEL_NONE;
1031}
1032
1034{
1035 const TreeElementSequenceStripDuplicate *te_dup =
1037 const Sequence *seq = &te_dup->get_sequence();
1038 if (seq->flag & SELECT) {
1039 return OL_DRAWSEL_NORMAL;
1040 }
1041 return OL_DRAWSEL_NONE;
1042}
1043
1045{
1046 if (((const bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) {
1047 return OL_DRAWSEL_NORMAL;
1048 }
1049 return OL_DRAWSEL_NONE;
1050}
1051
1053{
1054 GreasePencil &grease_pencil = *(GreasePencil *)te->store_elem->id;
1056 if (node.is_layer() && grease_pencil.is_layer_active(&node.as_layer())) {
1057 return OL_DRAWSEL_NORMAL;
1058 }
1059 return OL_DRAWSEL_NONE;
1060}
1061
1063{
1064 const ViewLayer *view_layer = CTX_data_view_layer(C);
1065 const LayerCollection *active = CTX_data_layer_collection(C);
1066
1067 if (active == view_layer->layer_collections.first) {
1068 return OL_DRAWSEL_NORMAL;
1069 }
1070 return OL_DRAWSEL_NONE;
1071}
1072
1074 const TreeElement *te)
1075{
1076 const LayerCollection *active = CTX_data_layer_collection(C);
1077 if (active == te->directdata) {
1078 return OL_DRAWSEL_NORMAL;
1079 }
1080 return OL_DRAWSEL_NONE;
1081}
1082
1084 ViewLayer *view_layer,
1085 const TreeElement *te)
1086{
1087 /* we search for the object parent */
1088 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1089 /* NOTE: `ob->matbits` can be nullptr when a local object points to a library mesh. */
1090 BKE_view_layer_synced_ensure(scene, view_layer);
1091 if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
1092 ob->matbits == nullptr)
1093 {
1094 return OL_DRAWSEL_NONE; /* just paranoia */
1095 }
1096
1097 /* searching in ob mat array? */
1098 const TreeElement *tes = te->parent;
1099 if (tes->idcode == ID_OB) {
1100 if (ob->actcol == te->index + 1) {
1101 if (ob->matbits[te->index]) {
1102 return OL_DRAWSEL_NORMAL;
1103 }
1104 }
1105 }
1106 /* or we search for obdata material */
1107 else {
1108 if (ob->actcol == te->index + 1) {
1109 if (ob->matbits[te->index] == 0) {
1110 return OL_DRAWSEL_NORMAL;
1111 }
1112 }
1113 }
1114 return OL_DRAWSEL_NONE;
1115}
1116
1118 const TreeElement *te,
1119 const TreeStoreElem *tselem)
1120{
1121 if (te->idcode == ID_SCE) {
1122 if (tselem->id == (ID *)tvc->scene) {
1123 return OL_DRAWSEL_NORMAL;
1124 }
1125 }
1126 return OL_DRAWSEL_NONE;
1127}
1128
1130{
1131 const TreeElement *tep = te->parent;
1132 if (tep == nullptr) {
1133 return OL_DRAWSEL_NORMAL;
1134 }
1135
1136 const TreeStoreElem *tselem = TREESTORE(tep);
1137 if (tselem->id == (const ID *)scene) {
1138 return OL_DRAWSEL_NORMAL;
1139 }
1140 return OL_DRAWSEL_NONE;
1141}
1142
1144{
1145 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1146
1147 return (scene->camera == ob) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
1148}
1149
1151 const TreeElement *te,
1152 const TreeStoreElem *tselem)
1153{
1154 switch (te->idcode) {
1155 case ID_SCE:
1156 return tree_element_active_scene_get(tvc, te, tselem);
1157 case ID_OB:
1158 /* Objects are currently handled by the caller in order to also change text color. */
1159 return OL_DRAWSEL_NONE;
1160 break;
1161 case ID_MA:
1162 return tree_element_active_material_get(tvc->scene, tvc->view_layer, te);
1163 case ID_WO:
1164 return tree_element_active_world_get(tvc->scene, te);
1165 case ID_CA:
1166 return tree_element_active_camera_get(tvc->scene, te);
1167 }
1168 return OL_DRAWSEL_NONE;
1169}
1170
1172 const TreeViewContext *tvc,
1173 const TreeElement *te,
1174 const TreeStoreElem *tselem)
1175{
1176 switch (tselem->type) {
1177 case TSE_DEFGROUP:
1178 return tree_element_defgroup_state_get(tvc->scene, tvc->view_layer, te, tselem);
1179 case TSE_BONE:
1180 return tree_element_bone_state_get(tvc->scene, tvc->view_layer, te, tselem);
1181 case TSE_EBONE:
1183 case TSE_MODIFIER:
1184 return tree_element_modifier_state_get(te, tselem);
1186 return OL_DRAWSEL_NONE;
1187 case TSE_LINKED_OB:
1188 return tree_element_object_state_get(tvc, tselem);
1189 case TSE_LINKED_PSYS:
1190 return OL_DRAWSEL_NONE;
1191 case TSE_POSE_BASE:
1192 return tree_element_pose_state_get(tvc->scene, tvc->view_layer, tselem);
1193 case TSE_POSE_CHANNEL:
1194 return tree_element_posechannel_state_get(tvc->ob_pose, te, tselem);
1196 case TSE_CONSTRAINT:
1197 return OL_DRAWSEL_NONE;
1198 case TSE_R_LAYER:
1200 case TSE_SEQUENCE:
1201 return tree_element_sequence_state_get(tvc->scene, te);
1202 case TSE_SEQUENCE_DUP:
1204 case TSE_GP_LAYER:
1213 return tree_element_bone_collection_state_get(te, tselem);
1214 }
1215 return OL_DRAWSEL_NONE;
1216}
1217
1219{
1220 TreeStoreElem *tselem;
1221
1222 te = te->parent;
1223 while (te) {
1224 tselem = TREESTORE(te);
1225 if (tselem->type == TSE_POSE_CHANNEL) {
1226 *r_bone_te = te;
1227 return (bPoseChannel *)te->directdata;
1228 }
1229 te = te->parent;
1230 }
1231
1232 return nullptr;
1233}
1234
1236 PointerRNA *ptr,
1237 const int context)
1238{
1239 bScreen *screen = CTX_wm_screen(C);
1240
1241 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1242 if (area->spacetype != SPACE_PROPERTIES) {
1243 continue;
1244 }
1245
1246 SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
1247 if (ED_buttons_should_sync_with_outliner(C, sbuts, area)) {
1248 ED_buttons_set_context(C, sbuts, ptr, context);
1249 }
1250 }
1251}
1252
1254{
1255 PointerRNA ptr = {nullptr};
1256 int context = 0;
1257
1258 /* ID Types */
1259 if (tselem->type == TSE_SOME_ID) {
1260 ptr = RNA_id_pointer_create(tselem->id);
1261
1262 switch (te->idcode) {
1263 case ID_SCE:
1264 context = BCONTEXT_SCENE;
1265 break;
1266 case ID_OB:
1267 context = BCONTEXT_OBJECT;
1268 break;
1269 case ID_ME:
1270 case ID_CU_LEGACY:
1271 case ID_MB:
1272 case ID_IM:
1273 case ID_LT:
1274 case ID_LA:
1275 case ID_CA:
1276 case ID_KE:
1277 case ID_SPK:
1278 case ID_AR:
1279 case ID_GD_LEGACY:
1280 case ID_GP:
1281 case ID_LP:
1282 case ID_CV:
1283 case ID_PT:
1284 case ID_VO:
1285 context = BCONTEXT_DATA;
1286 break;
1287 case ID_MA:
1288 context = BCONTEXT_MATERIAL;
1289 break;
1290 case ID_WO:
1291 context = BCONTEXT_WORLD;
1292 break;
1293 }
1294 }
1295 else {
1296 switch (tselem->type) {
1297 case TSE_DEFGROUP_BASE:
1298 case TSE_DEFGROUP:
1299 ptr = RNA_id_pointer_create(tselem->id);
1300 context = BCONTEXT_DATA;
1301 break;
1303 case TSE_CONSTRAINT: {
1304 TreeElement *bone_te = nullptr;
1305 bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
1306
1307 if (pchan) {
1308 ptr = RNA_pointer_create(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan);
1309 context = BCONTEXT_BONE_CONSTRAINT;
1310 }
1311 else {
1312 ptr = RNA_id_pointer_create(tselem->id);
1313 context = BCONTEXT_CONSTRAINT;
1314 }
1315
1316 /* Expand the selected constraint in the properties editor. */
1317 if (tselem->type != TSE_CONSTRAINT_BASE) {
1319 }
1320 break;
1321 }
1322 case TSE_MODIFIER_BASE:
1323 case TSE_MODIFIER:
1324 ptr = RNA_id_pointer_create(tselem->id);
1325 context = BCONTEXT_MODIFIER;
1326
1327 if (tselem->type != TSE_MODIFIER_BASE) {
1329
1330 switch ((ModifierType)md->type) {
1332 context = BCONTEXT_PARTICLE;
1333 break;
1340 context = BCONTEXT_PHYSICS;
1341 break;
1342 default:
1343 break;
1344 }
1345
1346 if (context == BCONTEXT_MODIFIER) {
1348 }
1349 }
1350 break;
1352 break;
1354 case TSE_GPENCIL_EFFECT:
1355 ptr = RNA_id_pointer_create(tselem->id);
1356 context = BCONTEXT_SHADERFX;
1357
1358 if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
1360 }
1361 break;
1362 case TSE_BONE: {
1363 bArmature *arm = (bArmature *)tselem->id;
1364 Bone *bone = static_cast<Bone *>(te->directdata);
1365
1366 ptr = RNA_pointer_create(&arm->id, &RNA_Bone, bone);
1367 context = BCONTEXT_BONE;
1368 break;
1369 }
1370 case TSE_EBONE: {
1371 bArmature *arm = (bArmature *)tselem->id;
1372 EditBone *ebone = static_cast<EditBone *>(te->directdata);
1373
1374 ptr = RNA_pointer_create(&arm->id, &RNA_EditBone, ebone);
1375 context = BCONTEXT_BONE;
1376 break;
1377 }
1378 case TSE_POSE_CHANNEL: {
1379 Object *ob = (Object *)tselem->id;
1380 bArmature *arm = static_cast<bArmature *>(ob->data);
1381 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
1382
1383 ptr = RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan);
1384 context = BCONTEXT_BONE;
1385 break;
1386 }
1387 case TSE_POSE_BASE: {
1388 Object *ob = (Object *)tselem->id;
1389 bArmature *arm = static_cast<bArmature *>(ob->data);
1390
1391 ptr = RNA_pointer_create(&arm->id, &RNA_Armature, arm);
1392 context = BCONTEXT_DATA;
1393 break;
1394 }
1395 case TSE_R_LAYER: {
1396 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
1397
1398 ptr = RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer);
1399 context = BCONTEXT_VIEW_LAYER;
1400 break;
1401 }
1402 case TSE_LINKED_PSYS: {
1403 Object *ob = (Object *)tselem->id;
1404 ParticleSystem *psys = psys_get_current(ob);
1405
1406 ptr = RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys);
1407 context = BCONTEXT_PARTICLE;
1408 break;
1409 }
1410 case TSE_GP_LAYER:
1412 ptr = RNA_id_pointer_create(tselem->id);
1413 context = BCONTEXT_DATA;
1414 break;
1416 ptr = RNA_pointer_create(tselem->id, &RNA_Armature, tselem->id);
1417 context = BCONTEXT_DATA;
1418 break;
1420 ptr = RNA_pointer_create(tselem->id, &RNA_BoneCollection, te->directdata);
1421 context = BCONTEXT_DATA;
1422 break;
1424 ptr = RNA_pointer_create(tselem->id, &RNA_Collection, te->directdata);
1425 context = BCONTEXT_COLLECTION;
1426 break;
1427 }
1428 }
1429
1430 if (ptr.data) {
1432 }
1433}
1434
1435/* ================================================ */
1436
1444 const TreeViewContext *tvc,
1445 SpaceOutliner *space_outliner,
1446 TreeElement *te,
1447 TreeStoreElem *tselem,
1448 const bool extend,
1449 const bool recursive,
1450 const bool do_activate_data)
1451{
1452 /* Always makes active object, except for some specific types. */
1453 if (ELEM(tselem->type,
1457 TSE_EBONE,
1460 {
1461 /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several
1462 * objects, we do not want to switch out of edit mode (see #48328 for details). */
1463 }
1464 else if (do_activate_data) {
1466 tvc->scene,
1467 tvc->view_layer,
1468 te,
1469 (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND :
1471 recursive && tselem->type == TSE_SOME_ID);
1472 }
1473 else if (recursive && !(space_outliner->flag & SO_SYNC_SELECT)) {
1474 /* Selection of child objects in hierarchy when sync-selection is OFF. */
1475 tree_iterator::all(te->subtree, [&](TreeElement *te) {
1476 TreeStoreElem *tselem = TREESTORE(te);
1477 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1478 tselem->flag |= TSE_SELECTED;
1479 }
1480 });
1481 }
1482
1483 if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */
1484 if (do_activate_data == false) {
1485 /* Only select in outliner. */
1486 }
1487 else if (te->idcode == ID_SCE) {
1488 if (tvc->scene != (Scene *)tselem->id) {
1490 }
1491 }
1492 else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) {
1493 Collection *gr = (Collection *)tselem->id;
1494 BKE_view_layer_synced_ensure(tvc->scene, tvc->view_layer);
1495
1496 if (extend) {
1499 Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
1500 if (base && (base->flag & BASE_SELECTED)) {
1501 sel = object::BA_DESELECT;
1502 break;
1503 }
1504 }
1506
1508 Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
1509 if (base) {
1510 object::base_select(base, sel);
1511 }
1512 }
1514 }
1515 else {
1516 BKE_view_layer_base_deselect_all(tvc->scene, tvc->view_layer);
1517
1519 Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
1520 /* Object may not be in this scene */
1521 if (base != nullptr) {
1522 if ((base->flag & BASE_SELECTED) == 0) {
1524 }
1525 }
1526 }
1528 }
1529
1530 DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT);
1532 }
1533 else { /* Rest of types. */
1534 tree_element_activate(C, tvc, te, OL_SETSEL_NORMAL, false);
1535 }
1536 }
1537 else if (do_activate_data) {
1539 C, tvc, te, tselem, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive);
1540 }
1541}
1542
1544 SpaceOutliner *space_outliner,
1545 TreeElement *te,
1546 const short select_flag)
1547{
1548 TreeStoreElem *tselem = TREESTORE(te);
1549 const bool activate = select_flag & OL_ITEM_ACTIVATE;
1550 const bool extend = select_flag & OL_ITEM_EXTEND;
1551 const bool activate_data = select_flag & OL_ITEM_SELECT_DATA;
1552 const bool recursive = select_flag & OL_ITEM_RECURSIVE;
1553
1554 /* Clear previous active when activating and clear selection when not extending selection */
1555 const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
1556
1557 /* Do not clear the active and select flag when selecting hierarchies. */
1558 if (clear_flag && !recursive) {
1559 outliner_flag_set(*space_outliner, clear_flag, false);
1560 }
1561
1562 if (select_flag & OL_ITEM_SELECT) {
1563 tselem->flag |= TSE_SELECTED;
1564 }
1565 else {
1566 tselem->flag &= ~TSE_SELECTED;
1567 }
1568
1569 if (activate) {
1570 TreeViewContext tvc;
1572
1573 if (!recursive) {
1574 tselem->flag |= TSE_ACTIVE;
1575 }
1576
1578 &tvc,
1579 space_outliner,
1580 te,
1581 tselem,
1582 extend,
1583 select_flag & OL_ITEM_RECURSIVE,
1584 activate_data || space_outliner->flag & SO_SYNC_SELECT);
1585 }
1586}
1587
1589{
1590 /* If we're recursing, we need to know the collection of the selected item in order
1591 * to prevent selecting across collection boundaries. (Object hierarchies might cross
1592 * collection boundaries, i.e., children may be in different collections from their
1593 * parents.) */
1594 Collection *parent_collection = nullptr;
1595 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1596 parent_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1597 }
1598 else if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1599 parent_collection = BKE_collection_object_find(CTX_data_main(C),
1600 CTX_data_scene(C),
1601 nullptr,
1602 reinterpret_cast<Object *>(te->store_elem->id));
1603 }
1604 return parent_collection;
1605}
1606
1607static bool can_select_recursive(TreeElement *te, Collection *in_collection)
1608{
1609 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1610 return true;
1611 }
1612
1613 if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1614 /* Only actually select the object if
1615 * 1. We are not restricted to any collection, or
1616 * 2. The object is in fact in the given collection. */
1617 if (!in_collection || BKE_collection_has_object_recursive(
1618 in_collection, reinterpret_cast<Object *>(te->store_elem->id)))
1619 {
1620 return true;
1621 }
1622 }
1623
1624 return false;
1625}
1626
1627static void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
1628{
1629 LISTBASE_FOREACH (TreeElement *, te, lb) {
1630 TreeStoreElem *tselem = TREESTORE(te);
1631 /* Recursive selection only on collections or objects. */
1632 if (can_select_recursive(te, in_collection)) {
1633 tselem->flag = selecting ? (tselem->flag | TSE_SELECTED) : (tselem->flag & ~TSE_SELECTED);
1634 if (tselem->type == TSE_LAYER_COLLECTION) {
1635 /* Restrict sub-tree selections to this collection. This prevents undesirable behavior in
1636 * the edge-case where there is an object which is part of this collection, but which has
1637 * children that are part of another collection. */
1639 &te->subtree, selecting, static_cast<LayerCollection *>(te->directdata)->collection);
1640 }
1641 else {
1642 do_outliner_select_recursive(&te->subtree, selecting, in_collection);
1643 }
1644 }
1645 else {
1646 tselem->flag &= ~TSE_SELECTED;
1647 }
1648 }
1649}
1650
1652 TreeElement *active,
1653 TreeElement *cursor,
1654 bool selecting,
1655 const bool recurse,
1656 Collection *in_collection)
1657{
1658 LISTBASE_FOREACH (TreeElement *, te, lb) {
1659 TreeStoreElem *tselem = TREESTORE(te);
1660
1661 bool can_select = !recurse || can_select_recursive(te, in_collection);
1662
1663 /* Remember if we are selecting before we potentially change the selecting state. */
1664 bool selecting_before = selecting;
1665
1666 /* Set state for selection */
1667 if (ELEM(te, active, cursor)) {
1668 selecting = !selecting;
1669 }
1670
1671 if (can_select && (selecting_before || selecting)) {
1672 tselem->flag |= TSE_SELECTED;
1673 }
1674
1675 /* Don't look inside closed elements, unless we're forcing the recursion all the way down. */
1676 if (!(tselem->flag & TSE_CLOSED) || recurse) {
1677 /* If this tree element is a collection, then it sets
1678 * the precedent for inclusion of its sub-objects. */
1679 Collection *child_collection = in_collection;
1680 if (tselem->type == TSE_LAYER_COLLECTION) {
1681 child_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1682 }
1684 &te->subtree, active, cursor, selecting, recurse, child_collection);
1685 }
1686 }
1687
1688 return selecting;
1689}
1690
1691/* Select a range of items between cursor and active element */
1693 SpaceOutliner *space_outliner,
1694 TreeElement *cursor,
1695 const bool extend,
1696 const bool recurse,
1697 Collection *in_collection)
1698{
1699 TreeElement *active = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
1700
1701 /* If no active element exists, activate the element under the cursor */
1702 if (!active) {
1703 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1704 return;
1705 }
1706
1707 TreeStoreElem *tselem = TREESTORE(active);
1708 const bool active_selected = (tselem->flag & TSE_SELECTED);
1709
1710 if (!extend) {
1711 outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1712 }
1713
1714 /* Select active if under cursor */
1715 if (active == cursor) {
1716 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT);
1717 if (recurse) {
1718 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1719 }
1720 return;
1721 }
1722
1723 /* If active is not selected or visible, select and activate the element under the cursor */
1724 if (!active_selected || !outliner_is_element_visible(active)) {
1725 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1726 return;
1727 }
1728
1730 &space_outliner->tree, active, cursor, false, recurse, in_collection);
1731
1732 if (recurse) {
1733 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1734 /* Select children of active tree element. This is required when
1735 * range selecting from bottom to top, see #117224. */
1736 in_collection = outliner_collection_get_for_recursive(C, active);
1737 do_outliner_select_recursive(&active->subtree, true, in_collection);
1738 }
1739}
1740
1742 const ARegion *region,
1743 float view_co_x)
1744{
1745 return (view_co_x > region->v2d.cur.xmax - outliner_right_columns_width(space_outliner));
1746}
1747
1748bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
1749{
1750 if (!outliner_shows_mode_column(*space_outliner)) {
1751 return false;
1752 }
1753
1754 return view_mval[0] < UI_UNIT_X;
1755}
1756
1758 SpaceOutliner *space_outliner,
1759 const float view_mval[2])
1760{
1761 const Scene *scene = CTX_data_scene(C);
1762 ViewLayer *view_layer = CTX_data_view_layer(C);
1763 BKE_view_layer_synced_ensure(scene, view_layer);
1764 Object *obact = BKE_view_layer_active_object_get(view_layer);
1765
1766 return outliner_is_co_within_mode_column(space_outliner, view_mval) && obact &&
1767 obact->mode != OB_MODE_OBJECT;
1768}
1769
1776 const int mval[2],
1777 const bool extend,
1778 const bool use_range,
1779 const bool deselect_all,
1780 const bool recurse)
1781{
1782 ARegion *region = CTX_wm_region(C);
1783 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1784 TreeElement *te;
1785 float view_mval[2];
1786 bool changed = false, rebuild_tree = false;
1787
1788 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
1789
1790 if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) {
1791 return OPERATOR_CANCELLED;
1792 }
1793 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
1794 return OPERATOR_CANCELLED;
1795 }
1796
1797 if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
1798 if (deselect_all) {
1799 changed |= outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1800 }
1801 }
1802 /* Don't allow toggle on scene collection */
1803 else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
1805 {
1807 }
1808 else {
1809 /* The row may also contain children, if one is hovered we want this instead of current te. */
1810 bool merged_elements = false;
1811 bool is_over_icon = false;
1813 space_outliner, te, view_mval[0], &merged_elements, &is_over_icon);
1814
1815 /* If the selected icon was an aggregate of multiple elements, run the search popup */
1816 if (merged_elements) {
1817 merged_element_search_menu_invoke(C, te, activate_te);
1818 return OPERATOR_CANCELLED;
1819 }
1820
1821 TreeStoreElem *activate_tselem = TREESTORE(activate_te);
1822
1823 Collection *parent_collection = nullptr;
1824 if (recurse) {
1825 parent_collection = outliner_collection_get_for_recursive(C, activate_te);
1826 }
1827
1828 /* If we're not recursing (not double clicking), and we are extending or range selecting by
1829 * holding CTRL or SHIFT, ignore events when the cursor is over the icon. This disambiguates
1830 * the case where we are recursing *and* holding CTRL or SHIFT in order to extend or range
1831 * select recursively. */
1832 if (!recurse && (extend || use_range) && is_over_icon) {
1833 return OPERATOR_CANCELLED;
1834 }
1835
1836 if (use_range) {
1838 C, space_outliner, activate_te, extend, (recurse && is_over_icon), parent_collection);
1839 }
1840 else {
1841 const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
1842 view_mval[0]);
1843 /* Always select unless already active and selected. */
1844 bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE) ||
1845 !(activate_tselem->flag & TSE_SELECTED);
1846
1847 /* If we're CTRL+double-clicking and the element is already
1848 * selected, skip the activation and go straight to deselection. */
1849 if (extend && recurse && activate_tselem->flag & TSE_SELECTED) {
1850 select = false;
1851 }
1852
1853 const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
1854 (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
1855 (extend ? OL_ITEM_EXTEND : 0);
1856
1857 /* The recurse flag is set when the user double-clicks
1858 * to select everything in a collection or hierarchy. */
1859 if (recurse) {
1860 if (is_over_icon) {
1861 /* Select or deselect object hierarchy recursively. */
1862 outliner_item_select(C, space_outliner, activate_te, select_flag);
1863 do_outliner_select_recursive(&activate_te->subtree, select, parent_collection);
1864 }
1865 else {
1866 /* Double-clicked, but it wasn't on the icon. */
1868 }
1869 }
1870 else {
1871 outliner_item_select(C, space_outliner, activate_te, select_flag);
1872 }
1873
1874 /* Only switch properties editor tabs when icons are selected. */
1875 if (is_over_icon) {
1876 outliner_set_properties_tab(C, activate_te, activate_tselem);
1877 }
1878 }
1879
1880 changed = true;
1881 }
1882
1883 if (!changed) {
1884 return OPERATOR_CANCELLED;
1885 }
1886
1887 if (rebuild_tree) {
1888 ED_region_tag_redraw(region);
1889 }
1890 else {
1892 }
1893
1894 ED_outliner_select_sync_from_outliner(C, space_outliner);
1895
1896 return OPERATOR_FINISHED;
1897}
1898
1899/* Event can enter-key, then it opens/closes. */
1901{
1902 ARegion *region = CTX_wm_region(C);
1903
1904 const bool extend = RNA_boolean_get(op->ptr, "extend");
1905 const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
1906 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
1907 const bool recurse = RNA_boolean_get(op->ptr, "recurse");
1908
1909 int mval[2];
1910 WM_event_drag_start_mval(event, region, mval);
1911 return outliner_item_do_activate_from_cursor(C, mval, extend, use_range, deselect_all, recurse);
1912}
1913
1915{
1916 ot->name = "Select";
1917 ot->idname = "OUTLINER_OT_item_activate";
1918 ot->description = "Handle mouse clicks to select and activate items";
1919
1921
1923
1925
1926 PropertyRNA *prop;
1927 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
1929 prop = RNA_def_boolean(
1930 ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
1932
1933 prop = RNA_def_boolean(ot->srna,
1934 "deselect_all",
1935 false,
1936 "Deselect On Nothing",
1937 "Deselect all when nothing under the cursor");
1939
1940 prop = RNA_def_boolean(
1941 ot->srna, "recurse", false, "Recurse", "Select objects recursively from active element");
1943}
1944
1947/* -------------------------------------------------------------------- */
1952 SpaceOutliner *space_outliner,
1953 const rctf *rectf,
1954 const bool select)
1955{
1956 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1957 if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
1958 outliner_item_select(
1959 C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
1960 }
1961 });
1962}
1963
1965{
1966 Scene *scene = CTX_data_scene(C);
1967 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1968 ARegion *region = CTX_wm_region(C);
1969 rctf rectf;
1970
1971 const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
1972 const bool select = (sel_op != SEL_OP_SUB);
1973 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1974 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1975 }
1976
1978 UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
1979
1980 outliner_box_select(C, space_outliner, &rectf, select);
1981
1985
1986 ED_outliner_select_sync_from_outliner(C, space_outliner);
1987
1988 return OPERATOR_FINISHED;
1989}
1990
1992{
1993 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1994 ARegion *region = CTX_wm_region(C);
1995 float view_mval[2];
1996 const bool tweak = RNA_boolean_get(op->ptr, "tweak");
1997
1998 int mval[2];
1999 WM_event_drag_start_mval(event, region, mval);
2000 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
2001
2002 /* Find element clicked on */
2003 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
2004
2005 /* Pass through if click is over name or icons, or not tweak event */
2006 if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
2008 }
2009
2010 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
2012 }
2013
2014 return WM_gesture_box_invoke(C, op, event);
2015}
2016
2018{
2019 /* identifiers */
2020 ot->name = "Box Select";
2021 ot->idname = "OUTLINER_OT_select_box";
2022 ot->description = "Use box selection to select tree elements";
2023
2024 /* api callbacks */
2029
2031
2032 /* flags */
2034
2035 /* properties */
2036 PropertyRNA *prop;
2037
2038 prop = RNA_def_boolean(
2039 ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
2041
2044}
2045
2048/* -------------------------------------------------------------------- */
2052/* Given a tree element return the rightmost child that is visible in the outliner */
2054 TreeElement *te)
2055{
2056 while (te->subtree.last) {
2057 if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
2058 te = static_cast<TreeElement *>(te->subtree.last);
2059 }
2060 else {
2061 break;
2062 }
2063 }
2064 return te;
2065}
2066
2067/* Find previous visible element in the tree. */
2069{
2070 if (te->prev) {
2071 te = outliner_find_rightmost_visible_child(space_outliner, te->prev);
2072 }
2073 else if (te->parent) {
2074 /* Use parent if at beginning of list */
2075 te = te->parent;
2076 }
2077
2078 return te;
2079}
2080
2081/* Recursively search up the tree until a successor to a given element is found */
2083{
2084 TreeElement *successor = te;
2085 while (successor->parent) {
2086 if (successor->parent->next) {
2087 te = successor->parent->next;
2088 break;
2089 }
2090 successor = successor->parent;
2091 }
2092
2093 return te;
2094}
2095
2096/* Find next visible element in the tree */
2098{
2099 TreeStoreElem *tselem = TREESTORE(te);
2100
2101 if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
2102 te = static_cast<TreeElement *>(te->subtree.first);
2103 }
2104 else if (te->next) {
2105 te = te->next;
2106 }
2107 else {
2109 }
2110
2111 return te;
2112}
2113
2115 TreeElement *te,
2116 bool toggle_all)
2117{
2118 TreeStoreElem *tselem = TREESTORE(te);
2119
2120 if (TSELEM_OPEN(tselem, space_outliner)) {
2121 outliner_item_openclose(te, false, toggle_all);
2122 }
2123 /* Only walk up a level if the element is closed and not toggling expand */
2124 else if (!toggle_all && te->parent) {
2125 te = te->parent;
2126 }
2127
2128 return te;
2129}
2130
2132 TreeElement *te,
2133 bool toggle_all)
2134{
2135 TreeStoreElem *tselem = TREESTORE(te);
2136
2137 /* Only walk down a level if the element is open and not toggling expand */
2138 if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
2139 te = static_cast<TreeElement *>(te->subtree.first);
2140 }
2141 else {
2142 outliner_item_openclose(te, true, toggle_all);
2143 }
2144
2145 return te;
2146}
2147
2149 TreeElement *te,
2150 const int direction,
2151 const bool extend,
2152 const bool toggle_all)
2153{
2154 TreeStoreElem *tselem = TREESTORE(te);
2155
2156 switch (direction) {
2157 case UI_SELECT_WALK_UP:
2158 te = outliner_find_previous_element(space_outliner, te);
2159 break;
2161 te = outliner_find_next_element(space_outliner, te);
2162 break;
2164 te = outliner_walk_left(space_outliner, te, toggle_all);
2165 break;
2167 te = outliner_walk_right(space_outliner, te, toggle_all);
2168 break;
2169 }
2170
2171 /* If new element is already selected, deselect the previous element */
2172 TreeStoreElem *tselem_new = TREESTORE(te);
2173 if (extend) {
2174 tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
2175 (tselem->flag | TSE_SELECTED);
2176 }
2177
2178 return te;
2179}
2180
2181/* Find the active element to walk from, or set one if none exists.
2182 * Changed is set to true if the active element is found, or false if it was set */
2183static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner, bool *r_changed)
2184{
2185 TreeElement *active_te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
2186 *r_changed = false;
2187
2188 /* If no active element exists, use the first element in the tree */
2189 if (!active_te) {
2190 active_te = static_cast<TreeElement *>(space_outliner->tree.first);
2191 *r_changed = true;
2192 }
2193
2194 /* If the active element is not visible, activate the first visible parent element */
2195 if (!outliner_is_element_visible(active_te)) {
2196 while (!outliner_is_element_visible(active_te)) {
2197 active_te = active_te->parent;
2198 }
2199 *r_changed = true;
2200 }
2201
2202 return active_te;
2203}
2204
2205/* Scroll the outliner when the walk element reaches the top or bottom boundary */
2206static void outliner_walk_scroll(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te)
2207{
2208 /* Account for the header height */
2209 int y_max = region->v2d.cur.ymax - UI_UNIT_Y;
2210 int y_min = region->v2d.cur.ymin;
2211
2212 /* Scroll if walked position is beyond the border */
2213 if (te->ys > y_max) {
2214 outliner_scroll_view(space_outliner, region, te->ys - y_max);
2215 }
2216 else if (te->ys < y_min) {
2217 outliner_scroll_view(space_outliner, region, -(y_min - te->ys));
2218 }
2219}
2220
2221static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2222{
2223 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2224 ARegion *region = CTX_wm_region(C);
2225
2226 const short direction = RNA_enum_get(op->ptr, "direction");
2227 const bool extend = RNA_boolean_get(op->ptr, "extend");
2228 const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
2229
2230 bool changed;
2231 TreeElement *active_te = find_walk_select_start_element(space_outliner, &changed);
2232
2233 /* If finding the active element did not modify the selection, proceed to walk */
2234 if (!changed) {
2235 active_te = do_outliner_select_walk(space_outliner, active_te, direction, extend, toggle_all);
2236 }
2237
2239 space_outliner,
2240 active_te,
2242
2243 /* Scroll outliner to focus on walk element */
2244 outliner_walk_scroll(space_outliner, region, active_te);
2245
2246 ED_outliner_select_sync_from_outliner(C, space_outliner);
2248
2249 return OPERATOR_FINISHED;
2250}
2251
2253{
2254 /* identifiers */
2255 ot->name = "Walk Select";
2256 ot->idname = "OUTLINER_OT_select_walk";
2257 ot->description = "Use walk navigation to select tree elements";
2258
2259 /* api callbacks */
2262
2264
2265 /* properties */
2266 PropertyRNA *prop;
2268 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
2270 prop = RNA_def_boolean(
2271 ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
2273}
2274
2277} // namespace blender::ed::outliner
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
bool ANIM_bone_is_visible_editbone(const bArmature *armature, const EditBone *ebone)
bool ANIM_bone_is_visible(const bArmature *armature, const Bone *bone)
#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)
LayerCollection * CTX_data_layer_collection(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:606
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:601
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:2456
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:534
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx)
Definition shader_fx.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#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:1021
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ 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
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ 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_BONE_COLLECTION
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_MODIFIER_BASE
@ TSE_GP_LAYER
@ TSE_SEQUENCE_DUP
@ TSE_SEQUENCE
@ TSE_GPENCIL_EFFECT
@ TSE_LINKED_NODE_TREE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_EBONE
@ TSE_BONE
@ TSE_LINKED_PSYS
@ TSE_DEFGROUP_BASE
@ TSE_CONSTRAINT
@ TSE_LAYER_COLLECTION
@ TSE_GREASE_PENCIL_NODE
@ TSE_SEQ_STRIP
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_LINKED_OB
@ TSE_SOME_ID
@ TSE_MODIFIER
@ TSE_BONE_COLLECTION_BASE
@ TSE_R_LAYER
@ TSE_POSE_BASE
@ TSE_DEFGROUP
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_ACTIVE
#define BASE_SELECTED(v3d, base)
@ SCE_OBJECT_MODE_LOCK
@ 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_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:653
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
bool ED_operator_outliner_active(bContext *C)
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ UI_SELECT_WALK_RIGHT
@ UI_SELECT_WALK_UP
@ UI_SELECT_WALK_LEFT
@ UI_SELECT_WALK_DOWN
eSelectOp
@ SEL_OP_SUB
bool ED_sequencer_deselect_all(Scene *scene)
bool ED_text_activate_in_screen(bContext *C, Text *text)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
void ED_undo_group_begin(bContext *C)
Definition ed_undo.cc:92
void ED_undo_group_end(bContext *C)
Definition ed_undo.cc:98
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#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:1663
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1670
#define ND_SEQUENCER
Definition WM_types.hh:404
#define NA_ACTIVATED
Definition WM_types.hh:556
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DATA
Definition WM_types.hh:475
#define NC_SCREEN
Definition WM_types.hh:344
#define ND_MODE
Definition WM_types.hh:412
#define ND_OB_SELECT
Definition WM_types.hh:409
#define NC_SCENE
Definition WM_types.hh:345
#define ND_MODIFIER
Definition WM_types.hh:429
#define NA_EDITED
Definition WM_types.hh:550
#define ND_PARTICLE
Definition WM_types.hh:432
#define NS_MODE_OBJECT
Definition WM_types.hh:526
#define NC_MATERIAL
Definition WM_types.hh:347
#define ND_CONSTRAINT
Definition WM_types.hh:431
#define NC_GPENCIL
Definition WM_types.hh:366
#define ND_BONE_ACTIVE
Definition WM_types.hh:426
#define ND_TRANSFORM
Definition WM_types.hh:423
#define ND_LAYER
Definition WM_types.hh:417
#define ND_BONE_COLLECTION
Definition WM_types.hh:441
#define NS_MODE_POSE
Definition WM_types.hh:535
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_SHADING_LINKS
Definition WM_types.hh:446
#define NS_LAYER_COLLECTION
Definition WM_types.hh:546
#define NA_SELECTED
Definition WM_types.hh:555
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)
void activate(bool forceActivation=false) const
#define SELECT
const Depsgraph * depsgraph
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
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(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 eOLDrawState tree_element_layer_collection_state_get(const bContext *C, const TreeElement *te)
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 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 void tree_element_sequence_dup_activate(Scene *scene, TreeElement *)
static eOLDrawState tree_element_active_camera_get(const Scene *scene, const TreeElement *te)
static eOLDrawState tree_element_pose_state_get(const Scene *scene, const ViewLayer *view_layer, const TreeStoreElem *tselem)
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_object_state_get(const TreeViewContext *tvc, const TreeStoreElem *tselem)
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_sequence_dup_state_get(const TreeElement *te)
static int outliner_box_select_exec(bContext *C, wmOperator *op)
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 int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 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_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)
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 int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te)
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)
void outliner_item_mode_toggle(bContext *C, TreeViewContext *tvc, TreeElement *te, bool do_extend)
bPoseChannel * outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te)
static TreeElement * outliner_find_previous_element(SpaceOutliner *space_outliner, TreeElement *te)
static TreeElement * do_outliner_select_walk(SpaceOutliner *space_outliner, TreeElement *te, const int direction, const bool extend, const bool toggle_all)
eOLDrawState tree_element_type_active_state_get(const bContext *C, const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
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_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)
void tree_element_type_active_set(bContext *C, const TreeViewContext *tvc, TreeElement *te, TreeStoreElem *tselem, eOLSetState set, bool recursive)
eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
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 do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
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 eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const TreeElement *te)
static void tree_element_psys_activate(bContext *C, TreeStoreElem *tselem)
static eOLDrawState tree_element_grease_pencil_node_state_get(const TreeElement *te)
static eOLDrawState tree_element_active_scene_get(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
static int 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 void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
static TreeElement * outliner_find_rightmost_visible_child(SpaceOutliner *space_outliner, TreeElement *te)
static void tree_element_sequence_activate(bContext *C, Scene *scene, TreeElement *te, const eOLSetState set)
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_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel)
static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *)
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)
static eOLDrawState tree_element_modifier_state_get(const TreeElement *te, const TreeStoreElem *tselem)
static void tree_element_text_activate(bContext *C, TreeElement *te)
void OUTLINER_OT_select_box(wmOperatorType *ot)
static eOLDrawState tree_element_master_collection_state_get(const bContext *C)
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 tree_element_activate(bContext *C, const TreeViewContext *tvc, TreeElement *te, eOLSetState set, bool handle_all_types)
void outliner_item_select(bContext *C, SpaceOutliner *space_outliner, TreeElement *te, short select_flag)
static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const TreeElement *te)
static void tree_element_object_activate(bContext *C, Scene *scene, ViewLayer *view_layer, TreeElement *te, const eOLSetState set, bool recursive)
#define TREESTORE(a)
#define TSELEM_OPEN(telm, sv)
bool ED_object_posemode_enter_ex(Main *bmain, Object *ob)
Definition pose_edit.cc:78
bool ED_object_posemode_exit_ex(Main *bmain, Object *ob)
Definition pose_edit.cc:113
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(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)
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void SEQ_select_active_set(Scene *scene, Sequence *seq)
short flag
struct Object * object
ListBase childbase
EditBone * next
ListBase * seqbasep
Sequence * act_seq
Definition DNA_ID.h:413
struct Collection * collection
void * last
void * first
ListBase wm
Definition BKE_main.hh:239
struct bPose * pose
char * matbits
void * data
Definition RNA_types.hh:42
struct Sequence * next
char filename[256]
StripElem * stripdata
ListBase layer_collections
struct BoneCollection * active_collection
struct EditBone * act_edbone
struct bArmature_Runtime runtime
struct Bone * bone
ListBase chanbase
float ymax
float ymin
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
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:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(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)