Blender V5.0
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) {
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->flag &= ~POSE_SELECTED;
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->flag & POSE_SELECTED)) {
577 pchan->flag &= ~POSE_SELECTED;
578 }
579 else {
580 if (blender::animrig::bone_is_visible(arm, pchan)) {
581 pchan->flag |= POSE_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->flag & POSE_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 WorkSpace *workspace,
734 TreeElement *te,
735 const eOLSetState set)
736{
737 Scene *sequencer_scene = workspace->sequencer_scene;
738 if (!sequencer_scene) {
739 return;
740 }
742 Strip *strip = &te_strip->get_strip();
743 Editing *ed = seq::editing_get(sequencer_scene);
744
745 if (BLI_findindex(ed->current_strips(), strip) != -1) {
746 if (set == OL_SETSEL_EXTEND) {
747 seq::select_active_set(sequencer_scene, nullptr);
748 }
749 vse::deselect_all_strips(sequencer_scene);
750
751 if ((set == OL_SETSEL_EXTEND) && strip->flag & SELECT) {
752 strip->flag &= ~SELECT;
753 }
754 else {
755 strip->flag |= SELECT;
756 seq::select_active_set(sequencer_scene, strip);
757 }
758 }
759
761}
762
764{
765 Scene *sequencer_scene = workspace->sequencer_scene;
766 if (!sequencer_scene) {
767 return;
768 }
769 Editing *ed = seq::editing_get(sequencer_scene);
770
771#if 0
772 select_single_seq(strip, 1);
773#endif
774 Strip *p = static_cast<Strip *>(ed->current_strips()->first);
775 while (p) {
776 if ((!p->data) || (!p->data->stripdata) || (p->data->stripdata->filename[0] == '\0')) {
777 p = p->next;
778 continue;
779 }
780
781#if 0
782 if (STREQ(p->strip->stripdata->filename, strip->data->stripdata->filename)) {
783 select_single_seq(p, 0);
784 }
785#endif
786 p = p->next;
787 }
788}
789
791{
792 ViewLayer *view_layer = CTX_data_view_layer(C);
793 LayerCollection *layer_collection = static_cast<LayerCollection *>(
794 view_layer->layer_collections.first);
795 BKE_layer_collection_activate(view_layer, layer_collection);
796 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
797 * when only the active collection changes. */
799}
800
802{
803 Scene *scene = CTX_data_scene(C);
804 LayerCollection *layer_collection = static_cast<LayerCollection *>(te->directdata);
805 ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
806 BKE_layer_collection_activate(view_layer, layer_collection);
807 /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
808 * when only the active collection changes. */
810}
811
817
818/* ---------------------------------------------- */
819
821 const TreeViewContext &tvc,
822 TreeElement *te,
823 const eOLSetState set,
824 const bool handle_all_types)
825{
826 switch (te->idcode) {
830 case ID_OB:
831 if (handle_all_types) {
832 tree_element_object_activate(C, tvc.scene, tvc.view_layer, te, set, false);
833 }
834 break;
835 case ID_MA:
837 break;
838 case ID_WO:
840 break;
841 case ID_CA:
843 break;
844 case ID_TXT:
846 break;
847 }
848}
849
851 const TreeViewContext &tvc,
852 TreeElement *te,
853 TreeStoreElem *tselem,
854 const eOLSetState set,
855 bool recursive)
856{
858 switch (tselem->type) {
859 case TSE_DEFGROUP:
861 break;
862 case TSE_BONE:
863 tree_element_bone_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
864 break;
865 case TSE_EBONE:
866 tree_element_ebone_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
867 break;
868 case TSE_MODIFIER:
869 tree_element_modifier_activate(C, te, tselem, set);
870 break;
871 case TSE_LINKED_OB:
872 tree_element_object_activate(C, tvc.scene, tvc.view_layer, te, set, false);
873 break;
874 case TSE_LINKED_PSYS:
876 break;
877 case TSE_POSE_BASE:
878 return;
879 case TSE_POSE_CHANNEL:
880 tree_element_posechannel_activate(C, tvc.scene, tvc.view_layer, te, tselem, set, recursive);
881 break;
883 case TSE_CONSTRAINT:
884 tree_element_constraint_activate(C, tvc.scene, tvc.view_layer, te, tselem, set);
885 break;
886 case TSE_R_LAYER:
888 break;
891 break;
892 case TSE_STRIP:
894 break;
895 case TSE_STRIP_DUP:
897 break;
898 case TSE_GP_LAYER:
899 tree_element_gplayer_activate(C, te, tselem);
900 break;
903 break;
906 break;
909 break;
910 }
911}
912
914 ViewLayer *view_layer,
915 const TreeElement *te,
916 const TreeStoreElem *tselem)
917{
918 const Object *ob = (const Object *)tselem->id;
919 BKE_view_layer_synced_ensure(scene, view_layer);
920 if (ob == BKE_view_layer_active_object_get(view_layer)) {
921 if (BKE_object_defgroup_active_index_get(ob) == te->index + 1) {
922 return OL_DRAWSEL_NORMAL;
923 }
924 }
925 return OL_DRAWSEL_NONE;
926}
927
929 ViewLayer *view_layer,
930 const TreeElement *te,
931 const TreeStoreElem *tselem)
932{
933 const bArmature *arm = (const bArmature *)tselem->id;
934 const Bone *bone = static_cast<Bone *>(te->directdata);
935 BKE_view_layer_synced_ensure(scene, view_layer);
936 const Object *ob = BKE_view_layer_active_object_get(view_layer);
937 if (ob && ob->data == arm) {
938 if (bone->flag & BONE_SELECTED) {
939 return OL_DRAWSEL_NORMAL;
940 }
941 }
942 return OL_DRAWSEL_NONE;
943}
944
946{
947 const EditBone *ebone = static_cast<EditBone *>(te->directdata);
948 if (ebone->flag & BONE_SELECTED) {
949 return OL_DRAWSEL_NORMAL;
950 }
951 return OL_DRAWSEL_NONE;
952}
953
955 const TreeStoreElem *tselem)
956{
957 const Object *ob = (const Object *)tselem->id;
958 const ModifierData *md = (const ModifierData *)te->directdata;
959
961}
962
964 const TreeStoreElem *tselem)
965{
966 return (tselem->id == (const ID *)tvc.obact) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
967}
968
970 const ViewLayer *view_layer,
971 const TreeStoreElem *tselem)
972{
973 const Object *ob = (const Object *)tselem->id;
974 /* This will just lookup in a cache, it will not change the arguments. */
975 BKE_view_layer_synced_ensure(scene, (ViewLayer *)view_layer);
976 const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob);
977 if (base == nullptr) {
978 /* Armature not instantiated in current scene (e.g. inside an appended group). */
979 return OL_DRAWSEL_NONE;
980 }
981
982 if (ob->mode & OB_MODE_POSE) {
983 return OL_DRAWSEL_NORMAL;
984 }
985 return OL_DRAWSEL_NONE;
986}
987
989 const TreeElement *te,
990 const TreeStoreElem *tselem)
991{
992 const Object *ob = (const Object *)tselem->id;
993 const bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
994 if (ob == ob_pose && ob->pose) {
995 if (pchan->flag & POSE_SELECTED) {
996 return OL_DRAWSEL_NORMAL;
997 }
998 }
999 return OL_DRAWSEL_NONE;
1000}
1001
1003 const TreeElement *te)
1004{
1005 const ViewLayer *te_view_layer = static_cast<ViewLayer *>(te->directdata);
1006
1007 if (view_layer == te_view_layer) {
1008 return OL_DRAWSEL_NORMAL;
1009 }
1010 return OL_DRAWSEL_NONE;
1011}
1012
1014 const TreeStoreElem *tselem)
1015{
1016 const bArmature *arm = reinterpret_cast<const bArmature *>(tselem->id);
1017 const BoneCollection *bcoll = reinterpret_cast<const BoneCollection *>(te->directdata);
1018
1019 if (arm->runtime.active_collection == bcoll) {
1020 return OL_DRAWSEL_ACTIVE;
1021 }
1022 return OL_DRAWSEL_NONE;
1023}
1024
1026{
1027 const Scene *sequencer_scene = workspace->sequencer_scene;
1028 if (!sequencer_scene) {
1029 return OL_DRAWSEL_NONE;
1030 }
1032 const Strip *strip = &te_strip->get_strip();
1033 const Editing *ed = seq::editing_get(sequencer_scene);
1034
1035 if (ed && ed->act_strip == strip && strip->flag & SELECT) {
1036 return OL_DRAWSEL_NORMAL;
1037 }
1038 return OL_DRAWSEL_NONE;
1039}
1040
1042{
1044 const Strip *strip = &te_dup->get_strip();
1045 if (strip->flag & SELECT) {
1046 return OL_DRAWSEL_NORMAL;
1047 }
1048 return OL_DRAWSEL_NONE;
1049}
1050
1052{
1053 if (((const bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) {
1054 return OL_DRAWSEL_NORMAL;
1055 }
1056 return OL_DRAWSEL_NONE;
1057}
1058
1060{
1061 GreasePencil &grease_pencil = *(GreasePencil *)te->store_elem->id;
1063 if (node.is_layer() && grease_pencil.is_layer_active(&node.as_layer())) {
1064 return OL_DRAWSEL_NORMAL;
1065 }
1066 return OL_DRAWSEL_NONE;
1067}
1068
1070 const ViewLayer *view_layer, const LayerCollection *layer_collection)
1071{
1072 if (layer_collection == view_layer->layer_collections.first) {
1073 return OL_DRAWSEL_NORMAL;
1074 }
1075 return OL_DRAWSEL_NONE;
1076}
1077
1079 const LayerCollection *layer_collection, const TreeElement *te)
1080{
1081 if (layer_collection == te->directdata) {
1082 return OL_DRAWSEL_NORMAL;
1083 }
1084 return OL_DRAWSEL_NONE;
1085}
1086
1088 ViewLayer *view_layer,
1089 const TreeElement *te)
1090{
1091 /* we search for the object parent */
1092 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1093 /* NOTE: `ob->matbits` can be nullptr when a local object points to a library mesh. */
1094 BKE_view_layer_synced_ensure(scene, view_layer);
1095 if (ob == nullptr || ob != BKE_view_layer_active_object_get(view_layer) ||
1096 ob->matbits == nullptr)
1097 {
1098 return OL_DRAWSEL_NONE; /* just paranoia */
1099 }
1100
1101 /* searching in ob mat array? */
1102 const TreeElement *tes = te->parent;
1103 if (tes->idcode == ID_OB) {
1104 if (ob->actcol == te->index + 1) {
1105 if (ob->matbits[te->index]) {
1106 return OL_DRAWSEL_NORMAL;
1107 }
1108 }
1109 }
1110 /* or we search for obdata material */
1111 else {
1112 if (ob->actcol == te->index + 1) {
1113 if (ob->matbits[te->index] == 0) {
1114 return OL_DRAWSEL_NORMAL;
1115 }
1116 }
1117 }
1118 return OL_DRAWSEL_NONE;
1119}
1120
1122 const TreeElement *te,
1123 const TreeStoreElem *tselem)
1124{
1125 if (te->idcode == ID_SCE) {
1126 if (tselem->id == (ID *)tvc.scene) {
1127 return OL_DRAWSEL_NORMAL;
1128 }
1129 }
1130 return OL_DRAWSEL_NONE;
1131}
1132
1134{
1135 const TreeElement *tep = te->parent;
1136 if (tep == nullptr) {
1137 return OL_DRAWSEL_NORMAL;
1138 }
1139
1140 const TreeStoreElem *tselem = TREESTORE(tep);
1141 if (tselem->id == (const ID *)scene) {
1142 return OL_DRAWSEL_NORMAL;
1143 }
1144 return OL_DRAWSEL_NONE;
1145}
1146
1148{
1149 const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
1150
1151 return (scene->camera == ob) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
1152}
1153
1155 const TreeElement *te,
1156 const TreeStoreElem *tselem)
1157{
1158 switch (te->idcode) {
1159 case ID_SCE:
1160 return tree_element_active_scene_get(tvc, te, tselem);
1161 case ID_OB:
1162 /* Objects are currently handled by the caller in order to also change text color. */
1163 return OL_DRAWSEL_NONE;
1164 break;
1165 case ID_MA:
1167 case ID_WO:
1168 return tree_element_active_world_get(tvc.scene, te);
1169 case ID_CA:
1170 return tree_element_active_camera_get(tvc.scene, te);
1171 }
1172 return OL_DRAWSEL_NONE;
1173}
1174
1176 const TreeElement *te,
1177 const TreeStoreElem *tselem)
1178{
1179 switch (tselem->type) {
1180 case TSE_DEFGROUP:
1181 return tree_element_defgroup_state_get(tvc.scene, tvc.view_layer, te, tselem);
1182 case TSE_BONE:
1183 return tree_element_bone_state_get(tvc.scene, tvc.view_layer, te, tselem);
1184 case TSE_EBONE:
1186 case TSE_MODIFIER:
1187 return tree_element_modifier_state_get(te, tselem);
1189 return OL_DRAWSEL_NONE;
1190 case TSE_LINKED_OB:
1191 return tree_element_object_state_get(tvc, tselem);
1192 case TSE_LINKED_PSYS:
1193 return OL_DRAWSEL_NONE;
1194 case TSE_POSE_BASE:
1195 return tree_element_pose_state_get(tvc.scene, tvc.view_layer, tselem);
1196 case TSE_POSE_CHANNEL:
1197 return tree_element_posechannel_state_get(tvc.ob_pose, te, tselem);
1199 case TSE_CONSTRAINT:
1200 return OL_DRAWSEL_NONE;
1201 case TSE_R_LAYER:
1203 case TSE_STRIP:
1205 case TSE_STRIP_DUP:
1207 case TSE_GP_LAYER:
1216 return tree_element_bone_collection_state_get(te, tselem);
1217 }
1218 return OL_DRAWSEL_NONE;
1219}
1220
1222{
1223 TreeStoreElem *tselem;
1224
1225 te = te->parent;
1226 while (te) {
1227 tselem = TREESTORE(te);
1228 if (tselem->type == TSE_POSE_CHANNEL) {
1229 *r_bone_te = te;
1230 return (bPoseChannel *)te->directdata;
1231 }
1232 te = te->parent;
1233 }
1234
1235 return nullptr;
1236}
1237
1239 PointerRNA *ptr,
1240 const int context)
1241{
1242 bScreen *screen = CTX_wm_screen(C);
1243
1244 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1245 if (area->spacetype != SPACE_PROPERTIES) {
1246 continue;
1247 }
1248
1249 SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
1250 if (ED_buttons_should_sync_with_outliner(C, sbuts, area)) {
1251 ED_buttons_set_context(C, sbuts, ptr, context);
1252 }
1253 }
1254}
1255
1257{
1258 PointerRNA ptr = {};
1259 int context = 0;
1260
1261 /* ID Types */
1262 if (tselem->type == TSE_SOME_ID) {
1263 ptr = RNA_id_pointer_create(tselem->id);
1264
1265 switch (te->idcode) {
1266 case ID_SCE:
1267 context = BCONTEXT_SCENE;
1268 break;
1269 case ID_OB:
1270 context = BCONTEXT_OBJECT;
1271 break;
1272 case ID_ME:
1273 case ID_CU_LEGACY:
1274 case ID_MB:
1275 case ID_IM:
1276 case ID_LT:
1277 case ID_LA:
1278 case ID_CA:
1279 case ID_KE:
1280 case ID_SPK:
1281 case ID_AR:
1282 case ID_GD_LEGACY:
1283 case ID_GP:
1284 case ID_LP:
1285 case ID_CV:
1286 case ID_PT:
1287 case ID_VO:
1288 context = BCONTEXT_DATA;
1289 break;
1290 case ID_MA:
1291 context = BCONTEXT_MATERIAL;
1292 break;
1293 case ID_WO:
1294 context = BCONTEXT_WORLD;
1295 break;
1296 }
1297 }
1298 else {
1299 switch (tselem->type) {
1300 case TSE_DEFGROUP_BASE:
1301 case TSE_DEFGROUP:
1302 ptr = RNA_id_pointer_create(tselem->id);
1303 context = BCONTEXT_DATA;
1304 break;
1306 case TSE_CONSTRAINT: {
1307 TreeElement *bone_te = nullptr;
1308 bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
1309
1310 if (pchan) {
1311 ptr = RNA_pointer_create_discrete(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan);
1312 context = BCONTEXT_BONE_CONSTRAINT;
1313 }
1314 else {
1315 ptr = RNA_id_pointer_create(tselem->id);
1316 context = BCONTEXT_CONSTRAINT;
1317 }
1318
1319 /* Expand the selected constraint in the properties editor. */
1320 if (tselem->type != TSE_CONSTRAINT_BASE) {
1322 }
1323 break;
1324 }
1325 case TSE_MODIFIER_BASE:
1326 case TSE_MODIFIER:
1327 ptr = RNA_id_pointer_create(tselem->id);
1328 context = BCONTEXT_MODIFIER;
1329
1330 if (tselem->type != TSE_MODIFIER_BASE) {
1332
1333 switch ((ModifierType)md->type) {
1335 context = BCONTEXT_PARTICLE;
1336 break;
1343 context = BCONTEXT_PHYSICS;
1344 break;
1345 default:
1346 break;
1347 }
1348
1349 if (context == BCONTEXT_MODIFIER) {
1351 }
1352 }
1353 break;
1355 break;
1357 case TSE_GPENCIL_EFFECT:
1358 ptr = RNA_id_pointer_create(tselem->id);
1359 context = BCONTEXT_SHADERFX;
1360
1361 if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
1363 }
1364 break;
1365 case TSE_BONE: {
1366 bArmature *arm = (bArmature *)tselem->id;
1367 Bone *bone = static_cast<Bone *>(te->directdata);
1368
1369 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Bone, bone);
1370 context = BCONTEXT_BONE;
1371 break;
1372 }
1373 case TSE_EBONE: {
1374 bArmature *arm = (bArmature *)tselem->id;
1375 EditBone *ebone = static_cast<EditBone *>(te->directdata);
1376
1377 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_EditBone, ebone);
1378 context = BCONTEXT_BONE;
1379 break;
1380 }
1381 case TSE_POSE_CHANNEL: {
1382 Object *ob = (Object *)tselem->id;
1383 bArmature *arm = static_cast<bArmature *>(ob->data);
1384 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
1385
1386 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_PoseBone, pchan);
1387 context = BCONTEXT_BONE;
1388 break;
1389 }
1390 case TSE_POSE_BASE: {
1391 Object *ob = (Object *)tselem->id;
1392 bArmature *arm = static_cast<bArmature *>(ob->data);
1393
1394 ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Armature, arm);
1395 context = BCONTEXT_DATA;
1396 break;
1397 }
1398 case TSE_R_LAYER: {
1399 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
1400
1401 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_ViewLayer, view_layer);
1402 context = BCONTEXT_VIEW_LAYER;
1403 break;
1404 }
1405 case TSE_LINKED_PSYS: {
1406 Object *ob = (Object *)tselem->id;
1407 ParticleSystem *psys = psys_get_current(ob);
1408
1409 ptr = RNA_pointer_create_discrete(&ob->id, &RNA_ParticleSystem, psys);
1410 context = BCONTEXT_PARTICLE;
1411 break;
1412 }
1413 case TSE_GP_LAYER:
1415 ptr = RNA_id_pointer_create(tselem->id);
1416 context = BCONTEXT_DATA;
1417 break;
1419 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Armature, tselem->id);
1420 context = BCONTEXT_DATA;
1421 break;
1423 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_BoneCollection, te->directdata);
1424 context = BCONTEXT_DATA;
1425 break;
1427 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Collection, te->directdata);
1428 context = BCONTEXT_COLLECTION;
1429 break;
1430 }
1431 }
1432
1433 if (ptr.data) {
1435 }
1436}
1437
1438/* ================================================ */
1439
1447 const TreeViewContext &tvc,
1448 SpaceOutliner *space_outliner,
1449 TreeElement *te,
1450 TreeStoreElem *tselem,
1451 const bool extend,
1452 const bool recursive,
1453 const bool do_activate_data)
1454{
1455 /* Always makes active object, except for some specific types. */
1456 if (ELEM(tselem->type,
1457 TSE_STRIP,
1460 TSE_EBONE,
1463 {
1464 /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several
1465 * objects, we do not want to switch out of edit mode (see #48328 for details). */
1466 }
1467 else if (do_activate_data) {
1469 tvc.scene,
1470 tvc.view_layer,
1471 te,
1472 (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND :
1474 recursive && tselem->type == TSE_SOME_ID);
1475 }
1476 else if (recursive && !(space_outliner->flag & SO_SYNC_SELECT)) {
1477 /* Selection of child objects in hierarchy when sync-selection is OFF. */
1478 tree_iterator::all(te->subtree, [&](TreeElement *te) {
1479 TreeStoreElem *tselem = TREESTORE(te);
1480 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1481 tselem->flag |= TSE_SELECTED;
1482 }
1483 });
1484 }
1485
1486 if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */
1487 if (do_activate_data == false) {
1488 /* Only select in outliner. */
1489 }
1490 else if (te->idcode == ID_SCE) {
1491 if (tvc.scene != (Scene *)tselem->id) {
1493 }
1494 }
1495 else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) {
1496 Collection *gr = (Collection *)tselem->id;
1497 BKE_view_layer_synced_ensure(tvc.scene, tvc.view_layer);
1498
1499 if (extend) {
1502 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1503 if (base && (base->flag & BASE_SELECTED)) {
1504 sel = object::BA_DESELECT;
1505 break;
1506 }
1507 }
1509
1511 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1512 if (base) {
1513 object::base_select(base, sel);
1514 }
1515 }
1517 }
1518 else {
1519 BKE_view_layer_base_deselect_all(tvc.scene, tvc.view_layer);
1520
1522 Base *base = BKE_view_layer_base_find(tvc.view_layer, object);
1523 /* Object may not be in this scene */
1524 if (base != nullptr) {
1525 if ((base->flag & BASE_SELECTED) == 0) {
1527 }
1528 }
1529 }
1531 }
1532
1533 DEG_id_tag_update(&tvc.scene->id, ID_RECALC_SELECT);
1535 }
1536 else { /* Rest of types. */
1537 tree_element_activate(C, tvc, te, OL_SETSEL_NORMAL, false);
1538 }
1539 }
1540 else if (do_activate_data) {
1542 C, tvc, te, tselem, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive);
1543 }
1544}
1545
1547 SpaceOutliner *space_outliner,
1548 TreeElement *te,
1549 const short select_flag)
1550{
1551 TreeStoreElem *tselem = TREESTORE(te);
1552 const bool activate = select_flag & OL_ITEM_ACTIVATE;
1553 const bool extend = select_flag & OL_ITEM_EXTEND;
1554 const bool activate_data = select_flag & OL_ITEM_SELECT_DATA;
1555 const bool recursive = select_flag & OL_ITEM_RECURSIVE;
1556
1557 /* Clear previous active when activating and clear selection when not extending selection */
1558 const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
1559
1560 /* Do not clear the active and select flag when selecting hierarchies. */
1561 if (clear_flag && !recursive) {
1562 outliner_flag_set(*space_outliner, clear_flag, false);
1563 }
1564
1565 if (select_flag & OL_ITEM_SELECT) {
1566 tselem->flag |= TSE_SELECTED;
1567 }
1568 else {
1569 tselem->flag &= ~TSE_SELECTED;
1570 }
1571
1572 if (activate) {
1573 TreeViewContext tvc;
1575
1576 if (!recursive) {
1577 tselem->flag |= TSE_ACTIVE;
1578 }
1579
1581 tvc,
1582 space_outliner,
1583 te,
1584 tselem,
1585 extend,
1586 select_flag & OL_ITEM_RECURSIVE,
1587 activate_data || space_outliner->flag & SO_SYNC_SELECT);
1588 }
1589}
1590
1592{
1593 /* If we're recursing, we need to know the collection of the selected item in order
1594 * to prevent selecting across collection boundaries. (Object hierarchies might cross
1595 * collection boundaries, i.e., children may be in different collections from their
1596 * parents.) */
1597 Collection *parent_collection = nullptr;
1598 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1599 parent_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1600 }
1601 else if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1602 parent_collection = BKE_collection_object_find(CTX_data_main(C),
1604 nullptr,
1605 reinterpret_cast<Object *>(te->store_elem->id));
1606 }
1607 return parent_collection;
1608}
1609
1610static bool can_select_recursive(TreeElement *te, Collection *in_collection)
1611{
1612 if (te->store_elem->type == TSE_LAYER_COLLECTION) {
1613 return true;
1614 }
1615
1616 if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
1617 /* Only actually select the object if
1618 * 1. We are not restricted to any collection, or
1619 * 2. The object is in fact in the given collection. */
1620 if (!in_collection || BKE_collection_has_object_recursive(
1621 in_collection, reinterpret_cast<Object *>(te->store_elem->id)))
1622 {
1623 return true;
1624 }
1625 }
1626
1627 return false;
1628}
1629
1630static void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
1631{
1632 LISTBASE_FOREACH (TreeElement *, te, lb) {
1633 TreeStoreElem *tselem = TREESTORE(te);
1634 /* Recursive selection only on collections or objects. */
1635 if (can_select_recursive(te, in_collection)) {
1636 tselem->flag = selecting ? (tselem->flag | TSE_SELECTED) : (tselem->flag & ~TSE_SELECTED);
1637 if (tselem->type == TSE_LAYER_COLLECTION) {
1638 /* Restrict sub-tree selections to this collection. This prevents undesirable behavior in
1639 * the edge-case where there is an object which is part of this collection, but which has
1640 * children that are part of another collection. */
1642 &te->subtree, selecting, static_cast<LayerCollection *>(te->directdata)->collection);
1643 }
1644 else {
1645 do_outliner_select_recursive(&te->subtree, selecting, in_collection);
1646 }
1647 }
1648 else {
1649 tselem->flag &= ~TSE_SELECTED;
1650 }
1651 }
1652}
1653
1656 TreeElement *cursor,
1657 bool selecting,
1658 const bool recurse,
1659 Collection *in_collection)
1660{
1661 LISTBASE_FOREACH (TreeElement *, te, lb) {
1662 TreeStoreElem *tselem = TREESTORE(te);
1663
1664 bool can_select = !recurse || can_select_recursive(te, in_collection);
1665
1666 /* Remember if we are selecting before we potentially change the selecting state. */
1667 bool selecting_before = selecting;
1668
1669 /* Set state for selection */
1670 if (ELEM(te, active, cursor)) {
1671 selecting = !selecting;
1672 }
1673
1674 if (can_select && (selecting_before || selecting)) {
1675 tselem->flag |= TSE_SELECTED;
1676 }
1677
1678 /* Don't look inside closed elements, unless we're forcing the recursion all the way down. */
1679 if (!(tselem->flag & TSE_CLOSED) || recurse) {
1680 /* If this tree element is a collection, then it sets
1681 * the precedent for inclusion of its sub-objects. */
1682 Collection *child_collection = in_collection;
1683 if (tselem->type == TSE_LAYER_COLLECTION) {
1684 child_collection = static_cast<LayerCollection *>(te->directdata)->collection;
1685 }
1687 &te->subtree, active, cursor, selecting, recurse, child_collection);
1688 }
1689 }
1690
1691 return selecting;
1692}
1693
1694/* Select a range of items between cursor and active element */
1696 SpaceOutliner *space_outliner,
1697 TreeElement *cursor,
1698 const bool extend,
1699 const bool recurse,
1700 Collection *in_collection)
1701{
1703
1704 /* If no active element exists, activate the element under the cursor */
1705 if (!active) {
1706 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1707 return;
1708 }
1709
1710 TreeStoreElem *tselem = TREESTORE(active);
1711 const bool active_selected = (tselem->flag & TSE_SELECTED);
1712
1713 if (!extend) {
1714 outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1715 }
1716
1717 /* Select active if under cursor */
1718 if (active == cursor) {
1719 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT);
1720 if (recurse) {
1721 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1722 }
1723 return;
1724 }
1725
1726 /* If active is not selected or visible, select and activate the element under the cursor */
1727 if (!active_selected || !outliner_is_element_visible(active)) {
1728 outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
1729 return;
1730 }
1731
1733 &space_outliner->tree, active, cursor, false, recurse, in_collection);
1734
1735 if (recurse) {
1736 do_outliner_select_recursive(&cursor->subtree, true, in_collection);
1737 /* Select children of active tree element. This is required when
1738 * range selecting from bottom to top, see #117224. */
1740 do_outliner_select_recursive(&active->subtree, true, in_collection);
1741 }
1742}
1743
1745 const ARegion *region,
1746 float view_co_x)
1747{
1748 return (view_co_x > region->v2d.cur.xmax - outliner_right_columns_width(space_outliner));
1749}
1750
1751bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
1752{
1753 if (!outliner_shows_mode_column(*space_outliner)) {
1754 return false;
1755 }
1756
1757 return view_mval[0] < UI_UNIT_X;
1758}
1759
1761 SpaceOutliner *space_outliner,
1762 const float view_mval[2])
1763{
1764 const Scene *scene = CTX_data_scene(C);
1765 ViewLayer *view_layer = CTX_data_view_layer(C);
1766 BKE_view_layer_synced_ensure(scene, view_layer);
1767 Object *obact = BKE_view_layer_active_object_get(view_layer);
1768
1769 return outliner_is_co_within_mode_column(space_outliner, view_mval) && obact &&
1770 obact->mode != OB_MODE_OBJECT;
1771}
1772
1779 const int mval[2],
1780 const bool extend,
1781 const bool use_range,
1782 const bool deselect_all,
1783 const bool recurse)
1784{
1785 ARegion *region = CTX_wm_region(C);
1786 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1787 TreeElement *te;
1788 float view_mval[2];
1789 bool changed = false, rebuild_tree = false;
1790
1791 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
1792
1793 if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) {
1794 return OPERATOR_CANCELLED;
1795 }
1796 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
1797 return OPERATOR_CANCELLED;
1798 }
1799
1800 if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
1801 if (deselect_all) {
1802 changed |= outliner_flag_set(*space_outliner, TSE_SELECTED, false);
1803 }
1804 }
1805 /* Don't allow toggle on scene collection */
1806 else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
1808 {
1810 }
1811 else {
1812 /* The row may also contain children, if one is hovered we want this instead of current te. */
1813 bool merged_elements = false;
1814 bool is_over_icon = false;
1816 space_outliner, te, view_mval[0], &merged_elements, &is_over_icon);
1817
1818 /* If the selected icon was an aggregate of multiple elements, run the search popup */
1819 if (merged_elements) {
1820 merged_element_search_menu_invoke(C, te, activate_te);
1821 return OPERATOR_CANCELLED;
1822 }
1823
1824 TreeStoreElem *activate_tselem = TREESTORE(activate_te);
1825
1826 Collection *parent_collection = nullptr;
1827 if (recurse) {
1828 parent_collection = outliner_collection_get_for_recursive(C, activate_te);
1829 }
1830
1831 /* If we're not recursing (not double clicking), and we are extending or range selecting by
1832 * holding CTRL or SHIFT, ignore events when the cursor is over the icon. This disambiguates
1833 * the case where we are recursing *and* holding CTRL or SHIFT in order to extend or range
1834 * select recursively. */
1835 if (!recurse && (extend || use_range) && is_over_icon) {
1836 return OPERATOR_CANCELLED;
1837 }
1838
1839 if (use_range) {
1841 C, space_outliner, activate_te, extend, (recurse && is_over_icon), parent_collection);
1842 }
1843 else {
1844 const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
1845 view_mval[0]);
1846 /* Always select unless already active and selected. */
1847 bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE) ||
1848 !(activate_tselem->flag & TSE_SELECTED);
1849
1850 /* If we're CTRL+double-clicking and the element is already
1851 * selected, skip the activation and go straight to deselection. */
1852 if (extend && recurse && activate_tselem->flag & TSE_SELECTED) {
1853 select = false;
1854 }
1855
1856 const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
1857 (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
1858 (extend ? OL_ITEM_EXTEND : 0);
1859
1860 /* The recurse flag is set when the user double-clicks
1861 * to select everything in a collection or hierarchy. */
1862 if (recurse) {
1863 if (is_over_icon) {
1864 /* Select or deselect object hierarchy recursively. */
1865 outliner_item_select(C, space_outliner, activate_te, select_flag);
1866 do_outliner_select_recursive(&activate_te->subtree, select, parent_collection);
1867 }
1868 else {
1869 /* Double-clicked, but it wasn't on the icon. */
1871 }
1872 }
1873 else {
1874 outliner_item_select(C, space_outliner, activate_te, select_flag);
1875 }
1876
1877 /* Only switch properties editor tabs when icons are selected. */
1878 if (is_over_icon) {
1879 outliner_set_properties_tab(C, activate_te, activate_tselem);
1880 }
1881 }
1882
1883 changed = true;
1884 }
1885
1886 if (!changed) {
1887 return OPERATOR_CANCELLED;
1888 }
1889
1890 if (rebuild_tree) {
1891 ED_region_tag_redraw(region);
1892 }
1893 else {
1895 }
1896
1898
1899 return OPERATOR_FINISHED;
1900}
1901
1902/* Event can enter-key, then it opens/closes. */
1904 wmOperator *op,
1905 const wmEvent *event)
1906{
1907 ARegion *region = CTX_wm_region(C);
1908
1909 const bool extend = RNA_boolean_get(op->ptr, "extend");
1910 const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
1911 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
1912 const bool recurse = RNA_boolean_get(op->ptr, "recurse");
1913
1914 int mval[2];
1915 WM_event_drag_start_mval(event, region, mval);
1916 return outliner_item_do_activate_from_cursor(C, mval, extend, use_range, deselect_all, recurse);
1917}
1918
1920{
1921 ot->name = "Select";
1922 ot->idname = "OUTLINER_OT_item_activate";
1923 ot->description = "Handle mouse clicks to select and activate items";
1924
1926
1928
1929 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1930
1931 PropertyRNA *prop;
1932 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
1934 prop = RNA_def_boolean(
1935 ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
1937
1938 prop = RNA_def_boolean(ot->srna,
1939 "deselect_all",
1940 false,
1941 "Deselect On Nothing",
1942 "Deselect all when nothing under the cursor");
1944
1945 prop = RNA_def_boolean(
1946 ot->srna, "recurse", false, "Recurse", "Select objects recursively from active element");
1948}
1949
1951
1952/* -------------------------------------------------------------------- */
1955
1957 SpaceOutliner *space_outliner,
1958 const rctf *rectf,
1959 const bool select)
1960{
1961 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1962 if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) {
1964 C, space_outliner, te, (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | OL_ITEM_EXTEND);
1965 }
1966 });
1967}
1968
1970{
1971 Scene *scene = CTX_data_scene(C);
1972 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1973 ARegion *region = CTX_wm_region(C);
1974 rctf rectf;
1975
1976 const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
1977 const bool select = (sel_op != SEL_OP_SUB);
1978 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1979 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1980 }
1981
1983 UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
1984
1985 outliner_box_select(C, space_outliner, &rectf, select);
1986
1990
1992
1993 return OPERATOR_FINISHED;
1994}
1995
1997 wmOperator *op,
1998 const wmEvent *event)
1999{
2000 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2001 ARegion *region = CTX_wm_region(C);
2002 float view_mval[2];
2003 const bool tweak = RNA_boolean_get(op->ptr, "tweak");
2004
2005 int mval[2];
2006 WM_event_drag_start_mval(event, region, mval);
2007 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
2008
2009 /* Find element clicked on */
2010 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
2011
2012 /* Pass through if click is over name or icons, or not tweak event */
2013 if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
2015 }
2016
2017 if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) {
2019 }
2020
2021 return WM_gesture_box_invoke(C, op, event);
2022}
2023
2025{
2026 /* identifiers */
2027 ot->name = "Box Select";
2028 ot->idname = "OUTLINER_OT_select_box";
2029 ot->description = "Use box selection to select tree elements";
2030
2031 /* API callbacks. */
2034 ot->modal = WM_gesture_box_modal;
2035 ot->cancel = WM_gesture_box_cancel;
2036
2038
2039 /* flags */
2040 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2041
2042 /* properties */
2043 PropertyRNA *prop;
2044
2045 prop = RNA_def_boolean(
2046 ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
2048
2051}
2052
2054
2055/* -------------------------------------------------------------------- */
2058
2059/* Given a tree element return the rightmost child that is visible in the outliner */
2061 TreeElement *te)
2062{
2063 while (te->subtree.last) {
2064 if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
2065 te = static_cast<TreeElement *>(te->subtree.last);
2066 }
2067 else {
2068 break;
2069 }
2070 }
2071 return te;
2072}
2073
2074/* Find previous visible element in the tree. */
2076{
2077 if (te->prev) {
2078 te = outliner_find_rightmost_visible_child(space_outliner, te->prev);
2079 }
2080 else if (te->parent) {
2081 /* Use parent if at beginning of list */
2082 te = te->parent;
2083 }
2084
2085 return te;
2086}
2087
2088/* Recursively search up the tree until a successor to a given element is found */
2090{
2091 TreeElement *successor = te;
2092 while (successor->parent) {
2093 if (successor->parent->next) {
2094 te = successor->parent->next;
2095 break;
2096 }
2097 successor = successor->parent;
2098 }
2099
2100 return te;
2101}
2102
2103/* Find next visible element in the tree */
2105{
2106 TreeStoreElem *tselem = TREESTORE(te);
2107
2108 if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
2109 te = static_cast<TreeElement *>(te->subtree.first);
2110 }
2111 else if (te->next) {
2112 te = te->next;
2113 }
2114 else {
2116 }
2117
2118 return te;
2119}
2120
2122 TreeElement *te,
2123 bool toggle_all)
2124{
2125 TreeStoreElem *tselem = TREESTORE(te);
2126
2127 if (TSELEM_OPEN(tselem, space_outliner)) {
2128 outliner_item_openclose(te, false, toggle_all);
2129 }
2130 /* Only walk up a level if the element is closed and not toggling expand */
2131 else if (!toggle_all && te->parent) {
2132 te = te->parent;
2133 }
2134
2135 return te;
2136}
2137
2139 TreeElement *te,
2140 bool toggle_all)
2141{
2142 TreeStoreElem *tselem = TREESTORE(te);
2143
2144 /* Only walk down a level if the element is open and not toggling expand */
2145 if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
2146 te = static_cast<TreeElement *>(te->subtree.first);
2147 }
2148 else {
2149 outliner_item_openclose(te, true, toggle_all);
2150 }
2151
2152 return te;
2153}
2154
2156 TreeElement *te,
2157 const int direction,
2158 const bool extend,
2159 const bool toggle_all)
2160{
2161 TreeStoreElem *tselem = TREESTORE(te);
2162
2163 switch (direction) {
2164 case UI_SELECT_WALK_UP:
2165 te = outliner_find_previous_element(space_outliner, te);
2166 break;
2168 te = outliner_find_next_element(space_outliner, te);
2169 break;
2171 te = outliner_walk_left(space_outliner, te, toggle_all);
2172 break;
2174 te = outliner_walk_right(space_outliner, te, toggle_all);
2175 break;
2176 }
2177
2178 /* If new element is already selected, deselect the previous element */
2179 TreeStoreElem *tselem_new = TREESTORE(te);
2180 if (extend) {
2181 tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
2182 (tselem->flag | TSE_SELECTED);
2183 }
2184
2185 return te;
2186}
2187
2188/* Find the active element to walk from, or set one if none exists.
2189 * Changed is set to true if the active element is found, or false if it was set */
2190static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner, bool *r_changed)
2191{
2192 TreeElement *active_te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
2193 *r_changed = false;
2194
2195 /* If no active element exists, use the first element in the tree */
2196 if (!active_te) {
2197 active_te = static_cast<TreeElement *>(space_outliner->tree.first);
2198 *r_changed = true;
2199 }
2200
2201 /* If the active element is not visible, activate the first visible parent element */
2202 if (!outliner_is_element_visible(active_te)) {
2203 while (!outliner_is_element_visible(active_te)) {
2204 active_te = active_te->parent;
2205 }
2206 *r_changed = true;
2207 }
2208
2209 return active_te;
2210}
2211
2212/* Scroll the outliner when the walk element reaches the top or bottom boundary */
2213static void outliner_walk_scroll(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te)
2214{
2215 /* Account for the header height */
2216 int y_max = region->v2d.cur.ymax - UI_UNIT_Y;
2217 int y_min = region->v2d.cur.ymin;
2218
2219 /* Scroll if walked position is beyond the border */
2220 if (te->ys > y_max) {
2221 outliner_scroll_view(space_outliner, region, te->ys - y_max);
2222 }
2223 else if (te->ys < y_min) {
2224 outliner_scroll_view(space_outliner, region, -(y_min - te->ys));
2225 }
2226}
2227
2229 wmOperator *op,
2230 const wmEvent * /*event*/)
2231{
2232 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2233 ARegion *region = CTX_wm_region(C);
2234
2235 const short direction = RNA_enum_get(op->ptr, "direction");
2236 const bool extend = RNA_boolean_get(op->ptr, "extend");
2237 const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
2238
2239 bool changed;
2240 TreeElement *active_te = find_walk_select_start_element(space_outliner, &changed);
2241
2242 /* If finding the active element did not modify the selection, proceed to walk */
2243 if (!changed) {
2244 active_te = do_outliner_select_walk(space_outliner, active_te, direction, extend, toggle_all);
2245 }
2246
2248 space_outliner,
2249 active_te,
2251
2252 /* Scroll outliner to focus on walk element */
2253 outliner_walk_scroll(space_outliner, region, active_te);
2254
2257
2258 return OPERATOR_FINISHED;
2259}
2260
2262{
2263 /* identifiers */
2264 ot->name = "Walk Select";
2265 ot->idname = "OUTLINER_OT_select_walk";
2266 ot->description = "Use walk navigation to select tree elements";
2267
2268 /* API callbacks. */
2271
2272 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2273
2274 /* properties */
2275 PropertyRNA *prop;
2277 prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
2279 prop = RNA_def_boolean(
2280 ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
2282}
2283
2285
2286} // 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)
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:612
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:607
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:2523
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:538
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
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:1054
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ 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
@ POSE_SELECTED
@ 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_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
@ 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_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:638
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
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:98
void ED_undo_group_begin(bContext *C)
Definition ed_undo.cc:86
void ED_undo_group_end(bContext *C)
Definition ed_undo.cc:92
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#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:1668
void UI_view2d_region_to_view_rctf(const View2D *v2d, const rctf *rect_src, rctf *rect_dst) ATTR_NONNULL()
Definition view2d.cc:1675
#define ND_SEQUENCER
Definition WM_types.hh:437
#define NA_ACTIVATED
Definition WM_types.hh:590
#define ND_DATA
Definition WM_types.hh:509
#define NC_SCREEN
Definition WM_types.hh:377
#define ND_MODE
Definition WM_types.hh:445
#define ND_OB_SELECT
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_MODIFIER
Definition WM_types.hh:462
#define NA_EDITED
Definition WM_types.hh:584
#define ND_PARTICLE
Definition WM_types.hh:465
#define NS_MODE_OBJECT
Definition WM_types.hh:560
#define NC_MATERIAL
Definition WM_types.hh:380
#define ND_CONSTRAINT
Definition WM_types.hh:464
#define NC_GPENCIL
Definition WM_types.hh:399
#define ND_BONE_ACTIVE
Definition WM_types.hh:459
#define ND_TRANSFORM
Definition WM_types.hh:456
#define ND_LAYER
Definition WM_types.hh:450
#define ND_BONE_COLLECTION
Definition WM_types.hh:474
#define NS_MODE_POSE
Definition WM_types.hh:569
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_SHADING_LINKS
Definition WM_types.hh:479
#define NS_LAYER_COLLECTION
Definition WM_types.hh:580
#define NA_SELECTED
Definition WM_types.hh:589
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)
bool bone_is_selectable(const bArmature *armature, const bPoseChannel *pchan)
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 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 tree_element_strip_activate(bContext *C, WorkSpace *workspace, TreeElement *te, const eOLSetState set)
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_material_activate(bContext *C, const Scene *scene, ViewLayer *view_layer, TreeElement *te)
static eOLDrawState tree_element_strip_state_get(const WorkSpace *workspace, const 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_dup_activate(WorkSpace *workspace, TreeElement *)
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:286
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:113
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:414
struct Collection * collection
void * last
void * first
ListBase wm
Definition BKE_main.hh:307
struct bPose * pose
char * matbits
struct ToolSettings * toolsettings
ListBase view_layers
struct Object * camera
StripElem * stripdata
char filename[256]
StripData * data
struct Strip * next
ListBase layer_collections
struct Scene * sequencer_scene
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237
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)