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