Blender V4.3
outliner_draw.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
14#include "DNA_light_types.h"
17#include "DNA_object_types.h"
18#include "DNA_scene_types.h"
19#include "DNA_sequence_types.h"
20#include "DNA_text_types.h"
21
22#include "BLI_blenlib.h"
23#include "BLI_string_utils.hh"
24#include "BLI_utildefines.h"
25
26#include "BLT_translation.hh"
27
28#include "BKE_armature.hh"
29#include "BKE_context.hh"
30#include "BKE_curve.hh"
31#include "BKE_deform.hh"
32#include "BKE_gpencil_legacy.h"
33#include "BKE_grease_pencil.hh"
34#include "BKE_idtype.hh"
35#include "BKE_layer.hh"
36#include "BKE_lib_id.hh"
37#include "BKE_lib_override.hh"
38#include "BKE_library.hh"
39#include "BKE_main.hh"
40#include "BKE_main_namemap.hh"
41#include "BKE_modifier.hh"
42#include "BKE_node.hh"
43#include "BKE_object.hh"
44#include "BKE_particle.h"
45#include "BKE_report.hh"
46
48
49#include "DEG_depsgraph.hh"
51
52#include "ED_armature.hh"
53#include "ED_fileselect.hh"
54#include "ED_id_management.hh"
55#include "ED_outliner.hh"
56#include "ED_screen.hh"
57#include "ED_undo.hh"
58
59#include "WM_api.hh"
60#include "WM_message.hh"
61#include "WM_types.hh"
62
63#include "GPU_immediate.hh"
64#include "GPU_state.hh"
65
66#include "UI_interface.hh"
67#include "UI_interface_icons.hh"
68#include "UI_resources.hh"
69#include "UI_view2d.hh"
70
71#include "RNA_access.hh"
72
73#include "outliner_intern.hh"
74#include "tree/tree_element.hh"
80#include "tree/tree_iterator.hh"
81
82namespace blender::ed::outliner {
83
84/* -------------------------------------------------------------------- */
88static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
89 ListBase *lb,
90 int *width,
91 int *height)
92{
93 LISTBASE_FOREACH (TreeElement *, te, lb) {
94 *width = std::max(*width, int(te->xend));
95 if (height != nullptr) {
96 *height += UI_UNIT_Y;
97 }
98
99 TreeStoreElem *tselem = TREESTORE(te);
100 if (TSELEM_OPEN(tselem, space_outliner)) {
101 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
102 }
103 else {
104 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
105 }
106 }
107}
108
109void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height)
110{
111 *r_width = 0;
112 *r_height = 0;
113 outliner_tree_dimensions_impl(space_outliner, &space_outliner->tree, r_width, r_height);
114}
115
119static bool is_object_data_in_editmode(const ID *id, const Object *obact)
120{
121 if (id == nullptr) {
122 return false;
123 }
124
125 const short id_type = GS(id->name);
126
127 if (id_type == ID_GD_LEGACY && obact && obact->data == id) {
128 bGPdata *gpd = (bGPdata *)id;
129 return GPENCIL_EDIT_MODE(gpd);
130 }
131
132 return ((obact && (obact->mode & OB_MODE_EDIT)) && (id && OB_DATA_SUPPORT_EDITMODE(id_type)) &&
133 (GS(((ID *)obact->data)->name) == id_type) && BKE_object_data_is_in_editmode(obact, id));
134}
135
138/* -------------------------------------------------------------------- */
143 EditBone *ebone_parent,
144 int flag,
145 bool set_flag)
146{
147 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
148 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
149 if (set_flag) {
150 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
151 ebone->flag |= flag;
152 }
153 else {
154 ebone->flag &= ~flag;
155 }
156 }
157 }
158}
159
160static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
161{
162 LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
163 if (set_flag) {
164 bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
165 bone->flag |= flag;
166 }
167 else {
168 bone->flag &= ~flag;
169 }
170 restrictbutton_recursive_bone(bone, flag, set_flag);
171 }
172}
173
174static void restrictbutton_r_lay_fn(bContext *C, void *poin, void * /*poin2*/)
175{
177}
178
179static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void * /*poin2*/)
180{
181 Bone *bone = (Bone *)poin;
182
185 }
186}
187
188static void restrictbutton_bone_select_fn(bContext *C, void *poin, void *poin2)
189{
190 bArmature *arm = static_cast<bArmature *>(poin);
191 Bone *bone = static_cast<Bone *>(poin2);
192
193 if (bone->flag & BONE_UNSELECTABLE) {
195 }
196
199 }
200
203}
204
205static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
206{
207 bArmature *arm = (bArmature *)poin;
208 EditBone *ebone = (EditBone *)poin2;
209
210 if (ebone->flag & BONE_UNSELECTABLE) {
212 }
213
216 arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
217 }
218
220}
221
222static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
223{
224 bArmature *arm = (bArmature *)poin;
225 EditBone *ebone = (EditBone *)poin2;
226 if (ebone->flag & BONE_HIDDEN_A) {
228 }
229
232 }
233
235}
236
237static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void * /*poin2*/)
238{
239 ID *id = (ID *)poin;
240
243}
244
245static void restrictbutton_id_user_toggle(bContext * /*C*/, void *poin, void * /*poin2*/)
246{
247 ID *id = (ID *)poin;
248
249 BLI_assert(id != nullptr);
250
251 if (id->flag & ID_FLAG_FAKEUSER) {
252 id_us_plus(id);
253 }
254 else {
255 id_us_min(id);
256 }
257}
258
260 Base *base,
261 Object *ob,
262 const char *propname)
263{
264 Main *bmain = CTX_data_main(C);
265 wmWindow *win = CTX_wm_window(C);
266 Scene *scene = CTX_data_scene(C);
267 ViewLayer *view_layer = CTX_data_view_layer(C);
268
269 bool extend = (win->eventstate->modifier & KM_SHIFT);
270
271 if (!extend) {
272 return;
273 }
274
275 /* Create PointerRNA and PropertyRNA for either Object or Base. */
276 ID *id = ob ? &ob->id : &scene->id;
277 StructRNA *struct_rna = ob ? &RNA_Object : &RNA_ObjectBase;
278 void *data = ob ? (void *)ob : (void *)base;
279
280 PointerRNA ptr = RNA_pointer_create(id, struct_rna, data);
281 PropertyRNA *base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname);
282 const bool value = RNA_property_boolean_get(&ptr, base_or_object_prop);
283
284 Object *ob_parent = ob ? ob : base->object;
285
286 for (Object *ob_iter = static_cast<Object *>(bmain->objects.first); ob_iter;
287 ob_iter = static_cast<Object *>(ob_iter->id.next))
288 {
289 if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
290 if (ob) {
291 ptr = RNA_id_pointer_create(&ob_iter->id);
293 }
294 else {
295 BKE_view_layer_synced_ensure(scene, view_layer);
296 Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
297 /* Child can be in a collection excluded from view-layer. */
298 if (base_iter == nullptr) {
299 continue;
300 }
301 ptr = RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter);
302 }
303 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
304 }
305 }
306
307 /* We don't call RNA_property_update() due to performance, so we batch update them. */
308 if (ob) {
311 }
312 else {
315 }
316}
317
321static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
322{
323 Object *ob = static_cast<Object *>(poin);
324 char *propname = static_cast<char *>(poin2);
325 outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
326}
327
331static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
332{
333 Base *base = static_cast<Base *>(poin);
334 char *propname = static_cast<char *>(poin2);
335 outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
336}
337
340 LayerCollection *layer_collection,
341 Collection *collection,
343{
344 if (collection) {
345 *ptr = RNA_id_pointer_create(&collection->id);
346 }
347 else {
348 *ptr = RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection);
349 }
350}
351
354 Scene *scene, ViewLayer *view_layer, Collection *collection, Object *ob, PointerRNA *ptr)
355{
356 if (collection) {
358 }
359 else {
360 BKE_view_layer_synced_ensure(scene, view_layer);
361 Base *base = BKE_view_layer_base_find(view_layer, ob);
362 *ptr = RNA_pointer_create(&scene->id, &RNA_ObjectBase, base);
363 }
364}
365
366/* NOTE: Collection is only valid when we want to change the collection data, otherwise we get it
367 * from layer collection. Layer collection is valid whenever we are looking at a view layer. */
369 ViewLayer *view_layer,
370 LayerCollection *layer_collection,
371 Collection *collection,
372 PropertyRNA *layer_or_collection_prop,
373 PropertyRNA *base_or_object_prop,
374 const bool value)
375{
376 if (layer_collection && layer_collection->flag & LAYER_COLLECTION_EXCLUDE) {
377 return;
378 }
380 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
381 if (layer_or_collection_prop && !RNA_property_editable(&ptr, layer_or_collection_prop)) {
382 return;
383 }
384
385 RNA_property_boolean_set(&ptr, layer_or_collection_prop, value);
386
387 /* Set the same flag for the nested objects as well. */
388 if (base_or_object_prop) {
389 /* NOTE: We can't use BKE_collection_object_cache_get()
390 * otherwise we would not take collection exclusion into account. */
391 LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
392
393 outliner_base_or_object_pointer_create(scene, view_layer, collection, cob->ob, &ptr);
394 if (!RNA_property_editable(&ptr, base_or_object_prop)) {
395 continue;
396 }
397
398 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
399
400 if (collection) {
402 }
403 }
404 }
405
406 /* Keep going recursively. */
407 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
408 LISTBASE_FOREACH (Link *, link, lb) {
409 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
410 Collection *collection_iter = layer_collection ?
411 (collection ? layer_collection_iter->collection : nullptr) :
412 ((CollectionChild *)link)->collection;
414 view_layer,
415 layer_collection_iter,
416 collection_iter,
417 layer_or_collection_prop,
418 base_or_object_prop,
419 value);
420 }
421
422 if (collection) {
424 }
425}
426
438 const LayerCollection *layer_collection_cmp,
439 const Collection *collection_cmp,
440 const bool value_cmp,
441 const PropertyRNA *layer_or_collection_prop,
442 LayerCollection *layer_collection,
443 Collection *collection)
444{
446 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
447 const bool value = RNA_property_boolean_get(&ptr, (PropertyRNA *)layer_or_collection_prop);
448 Collection *collection_ensure = collection ? collection : layer_collection->collection;
449 const Collection *collection_ensure_cmp = collection_cmp ? collection_cmp :
450 layer_collection_cmp->collection;
451
452 if (collection_ensure->flag & COLLECTION_IS_MASTER) {
453 }
454 else if (collection_ensure == collection_ensure_cmp) {
455 }
456 else if (BKE_collection_has_collection(collection_ensure, (Collection *)collection_ensure_cmp) ||
457 BKE_collection_has_collection((Collection *)collection_ensure_cmp, collection_ensure))
458 {
459 /* This collection is either a parent or a child of the collection.
460 * We expect it to be set "visible" already. */
461 if (value != value_cmp) {
462 return false;
463 }
464 }
465 else {
466 /* This collection is neither a parent nor a child of the collection.
467 * We expect it to be "invisible". */
468 if (value == value_cmp) {
469 return false;
470 }
471 }
472
473 /* Keep going recursively. */
474 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
475 LISTBASE_FOREACH (Link *, link, lb) {
476 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
477 Collection *collection_iter = layer_collection ?
478 (collection ? layer_collection_iter->collection : nullptr) :
479 ((CollectionChild *)link)->collection;
480 if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
481 continue;
482 }
484 layer_collection_cmp,
485 collection_cmp,
486 value_cmp,
487 layer_or_collection_prop,
488 layer_collection_iter,
489 collection_iter))
490 {
491 return false;
492 }
493 }
494
495 return true;
496}
497
499 ViewLayer *view_layer,
500 LayerCollection *layer_collection,
501 Collection *collection,
502 PropertyRNA *layer_or_collection_prop,
503 const char *propname,
504 const bool value)
505{
507 const bool is_hide = strstr(propname, "hide_") != nullptr;
508
509 LayerCollection *top_layer_collection = layer_collection ?
510 static_cast<LayerCollection *>(
511 view_layer->layer_collections.first) :
512 nullptr;
513 Collection *top_collection = collection ? scene->master_collection : nullptr;
514
515 bool was_isolated = (value == is_hide);
516 was_isolated &= outliner_collection_is_isolated(scene,
517 layer_collection,
518 collection,
519 !is_hide,
520 layer_or_collection_prop,
521 top_layer_collection,
522 top_collection);
523
524 if (was_isolated) {
525 const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
526 /* Make every collection go back to its default "visibility" state. */
528 view_layer,
529 top_layer_collection,
530 top_collection,
531 layer_or_collection_prop,
532 nullptr,
533 default_value);
534 return;
535 }
536
537 /* Make every collection "invisible". */
539 view_layer,
540 top_layer_collection,
541 top_collection,
542 layer_or_collection_prop,
543 nullptr,
544 is_hide);
545
546 /* Make this collection and its children collections the only "visible". */
548 view_layer,
549 layer_collection,
550 collection,
551 layer_or_collection_prop,
552 nullptr,
553 !is_hide);
554
555 /* Make this collection direct parents also "visible". */
556 if (layer_collection) {
557 LayerCollection *lc_parent = layer_collection;
558 LISTBASE_FOREACH (LayerCollection *, lc_iter, &top_layer_collection->layer_collections) {
559 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
560 lc_parent = lc_iter;
561 break;
562 }
563 }
564
565 while (lc_parent != layer_collection) {
567 scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
568 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
569
570 LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
571 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
572 lc_parent = lc_iter;
573 break;
574 }
575 }
576 }
577 }
578 else {
579 CollectionParent *parent;
580 Collection *child = collection;
581 while ((parent = static_cast<CollectionParent *>(child->runtime.parents.first))) {
582 if (parent->collection->flag & COLLECTION_IS_MASTER) {
583 break;
584 }
586 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
587 child = parent->collection;
588 }
589 }
590}
591
593 LayerCollection *layer_collection,
594 Collection *collection,
595 const char *propname)
596{
597 Main *bmain = CTX_data_main(C);
598 wmWindow *win = CTX_wm_window(C);
599 Scene *scene = CTX_data_scene(C);
600 ViewLayer *view_layer = CTX_data_view_layer(C);
601
602 bool do_isolate = (win->eventstate->modifier & KM_CTRL);
603 bool extend = (win->eventstate->modifier & KM_SHIFT);
604
605 if (!ELEM(true, do_isolate, extend)) {
606 return;
607 }
608
609 /* Create PointerRNA and PropertyRNA for either Collection or LayerCollection. */
610 ID *id = collection ? &collection->id : &scene->id;
611 StructRNA *struct_rna = collection ? &RNA_Collection : &RNA_LayerCollection;
612 void *data = collection ? (void *)collection : (void *)layer_collection;
613
614 PointerRNA ptr = RNA_pointer_create(id, struct_rna, data);
615 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
616 PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
617 const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
618
619 PropertyRNA *base_or_object_prop = nullptr;
620 if (layer_collection != nullptr) {
621 /* If we are toggling Layer collections we still want to change the properties of the base
622 * or the objects. If we have a matching property, toggle it as well, it can be nullptr. */
623 struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
624 base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname);
625 }
626
627 if (extend) {
629 view_layer,
630 layer_collection,
631 collection,
632 layer_or_collection_prop,
633 base_or_object_prop,
634 value);
635 }
636 else {
638 view_layer,
639 layer_collection,
640 collection,
641 layer_or_collection_prop,
642 propname,
643 value);
644 }
645
646 /* We don't call RNA_property_update() due to performance, so we batch update them. */
649}
650
656 void *poin,
657 void *poin2)
658{
659 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
660 char *propname = static_cast<char *>(poin2);
661 outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
662}
663
668static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
669{
670 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
671 char *propname = static_cast<char *>(poin2);
673 C, layer_collection, layer_collection->collection, propname);
674}
675
680static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
681{
682 Collection *collection = static_cast<Collection *>(poin);
683 char *propname = static_cast<char *>(poin2);
684 outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
685}
686
687static void namebutton_fn(bContext *C, void *tsep, char *oldname)
688{
689 Main *bmain = CTX_data_main(C);
690 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
691 wmMsgBus *mbus = CTX_wm_message_bus(C);
692 BLI_mempool *ts = space_outliner->treestore;
693 TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep);
694
695 const char *undo_str = nullptr;
696
697 /* Unfortunately at this point, the name of the ID has already been set to its new value. Revert
698 * it to its old name, to be able to use the generic 'rename' function for IDs.
699 *
700 * NOTE: While utterly inelegant, performances are not really a concern here, so this is an
701 * acceptable solution for now. */
702 auto id_rename_helper = [bmain, tselem, oldname]() -> bool {
703 std::string new_name = tselem->id->name + 2;
704 BLI_strncpy(tselem->id->name + 2, oldname, sizeof(tselem->id->name) - 2);
705 return ED_id_rename(*bmain, *tselem->id, new_name);
706 };
707
708 if (ts && tselem) {
709 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
710
711 if (ELEM(tselem->type, TSE_SOME_ID, TSE_LINKED_NODE_TREE)) {
712 if (id_rename_helper()) {
713 undo_str = "Rename Data-Block";
714 }
715
716 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
717
718 switch (GS(tselem->id->name)) {
719 case ID_MA:
721 break;
722 case ID_TE:
724 break;
725 case ID_IM:
726 WM_event_add_notifier(C, NC_IMAGE, nullptr);
727 break;
728 case ID_SCE:
729 WM_event_add_notifier(C, NC_SCENE, nullptr);
730 break;
731 default:
732 break;
733 }
735
736 /* Check the library target exists */
737 if (te->idcode == ID_LI) {
738 Library *lib = (Library *)tselem->id;
739 char expanded[FILE_MAX];
740
741 BKE_library_filepath_set(bmain, lib, lib->filepath);
742
743 STRNCPY(expanded, lib->filepath);
744 BLI_path_abs(expanded, BKE_main_blendfile_path(bmain));
745 if (!BLI_exists(expanded)) {
747 RPT_ERROR,
748 "Library path '%s' does not exist, correct this before saving",
749 expanded);
750 }
751 else if (lib->id.tag & ID_TAG_MISSING) {
753 RPT_INFO,
754 "Library path '%s' is now valid, please reload the library",
755 expanded);
756 lib->id.tag &= ~ID_TAG_MISSING;
757 }
758 }
759
761 }
762 else {
763 switch (tselem->type) {
764 case TSE_DEFGROUP: {
765 Object *ob = (Object *)tselem->id;
766 bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata);
768 WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
770 undo_str = "Rename Vertex Group";
771 break;
772 }
773 case TSE_NLA_ACTION: {
774 /* The #tselem->id is a #bAction. */
775 if (id_rename_helper()) {
776 undo_str = "Rename Data-Block";
777 }
778 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
780 break;
781 }
782 case TSE_NLA_TRACK: {
784 undo_str = "Rename NLA Track";
785 break;
786 }
787 case TSE_EBONE: {
788 bArmature *arm = (bArmature *)tselem->id;
789 if (arm->edbo) {
790 EditBone *ebone = static_cast<EditBone *>(te->directdata);
791 char newname[sizeof(ebone->name)];
792
793 /* restore bone name */
794 STRNCPY(newname, ebone->name);
795 STRNCPY(ebone->name, oldname);
796 ED_armature_bone_rename(bmain, arm, oldname, newname);
797 WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
800 undo_str = "Rename Edit Bone";
801 }
802 break;
803 }
804
805 case TSE_BONE: {
806 TreeViewContext tvc;
808
809 bArmature *arm = (bArmature *)tselem->id;
810 Bone *bone = static_cast<Bone *>(te->directdata);
811 char newname[sizeof(bone->name)];
812
813 /* always make current object active */
814 tree_element_activate(C, &tvc, te, OL_SETSEL_NORMAL, true);
815
816 /* restore bone name */
817 STRNCPY(newname, bone->name);
818 STRNCPY(bone->name, oldname);
819 ED_armature_bone_rename(bmain, arm, oldname, newname);
820 WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
823 undo_str = "Rename Bone";
824 break;
825 }
826 case TSE_POSE_CHANNEL: {
827 TreeViewContext tvc;
829
830 Object *ob = (Object *)tselem->id;
831 bArmature *arm = (bArmature *)ob->data;
832 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
833 char newname[sizeof(pchan->name)];
834
835 /* always make current pose-bone active */
836 tree_element_activate(C, &tvc, te, OL_SETSEL_NORMAL, true);
837
839
840 /* restore bone name */
841 STRNCPY(newname, pchan->name);
842 STRNCPY(pchan->name, oldname);
843 ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname);
844 WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
848 undo_str = "Rename Pose Bone";
849 break;
850 }
851 case TSE_GP_LAYER: {
852 bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
853 bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
854
855 /* always make layer active */
857
858 /* XXX: name needs translation stuff. */
860 &gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
861
862 WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, GPencilLayer, info);
866 undo_str = "Rename Grease Pencil Layer";
867 break;
868 }
870 GreasePencil &grease_pencil = *(GreasePencil *)tselem->id;
873
874 /* The node already has the new name set. To properly rename the node, we need to first
875 * store the new name, restore the old name in the node, and then call the rename
876 * function. */
877 std::string new_name(node.name());
878 node.set_name(oldname);
879 grease_pencil.rename_node(*bmain, node, new_name);
882 undo_str = "Rename Grease Pencil Drawing";
883 break;
884 }
885 case TSE_R_LAYER: {
886 Scene *scene = (Scene *)tselem->id;
887 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
888
889 /* Restore old name. */
890 char newname[sizeof(view_layer->name)];
891 STRNCPY(newname, view_layer->name);
892 STRNCPY(view_layer->name, oldname);
893
894 /* Rename, preserving animation and compositing data. */
895 BKE_view_layer_rename(bmain, scene, view_layer, newname);
896 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
899 undo_str = "Rename View Layer";
900 break;
901 }
903 /* The #tselem->id is a #Collection, not a #LayerCollection */
904 if (id_rename_helper()) {
905 undo_str = "Rename Data-Block";
906 }
907 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
910 break;
911 }
912
913 case TSE_BONE_COLLECTION: {
914 bArmature *arm = (bArmature *)tselem->id;
915 BoneCollection *bcoll = static_cast<BoneCollection *>(te->directdata);
916
917 ANIM_armature_bonecoll_name_set(arm, bcoll, bcoll->name);
918 WM_msg_publish_rna_prop(mbus, &arm->id, bcoll, BoneCollection, name);
921 undo_str = "Rename Bone Collection";
922 break;
923 }
924 }
925 }
926 tselem->flag &= ~TSE_TEXTBUT;
927 }
928
929 if (undo_str) {
930 ED_undo_push(C, undo_str);
931 }
932}
933
946
947/* We don't care about the value of the property
948 * but whether the property should be active or grayed out. */
966
968 PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
969{
970 if (props_active->collection_hide_render) {
972 collection_ptr, props->collection_hide_render);
973 if (!props_active->collection_hide_render) {
974 props_active->layer_collection_holdout = false;
975 props_active->layer_collection_indirect_only = false;
976 props_active->object_hide_render = false;
977 props_active->modifier_show_render = false;
978 props_active->constraint_enable = false;
979 }
980 }
981
982 if (props_active->collection_hide_viewport) {
984 collection_ptr, props->collection_hide_viewport);
985 if (!props_active->collection_hide_viewport) {
986 props_active->collection_hide_select = false;
987 props_active->object_hide_select = false;
988 props_active->layer_collection_hide_viewport = false;
989 props_active->object_hide_viewport = false;
990 props_active->base_hide_viewport = false;
991 props_active->modifier_show_viewport = false;
992 props_active->constraint_enable = false;
993 }
994 }
995
996 if (props_active->collection_hide_select) {
998 collection_ptr, props->collection_hide_select);
999 if (!props_active->collection_hide_select) {
1000 props_active->object_hide_select = false;
1001 }
1002 }
1003}
1004
1006 PointerRNA *layer_collection_ptr,
1007 PointerRNA *collection_ptr,
1008 RestrictProperties *props,
1009 RestrictPropertiesActive *props_active)
1010{
1011 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1012
1013 if (props_active->layer_collection_holdout) {
1015 layer_collection_ptr, props->layer_collection_holdout);
1016 }
1017
1018 if (props_active->layer_collection_indirect_only) {
1020 layer_collection_ptr, props->layer_collection_indirect_only);
1021 }
1022
1023 if (props_active->layer_collection_hide_viewport) {
1025 layer_collection_ptr, props->layer_collection_hide_viewport);
1026
1027 if (!props_active->layer_collection_hide_viewport) {
1028 props_active->base_hide_viewport = false;
1029 props_active->collection_hide_select = false;
1030 props_active->object_hide_select = false;
1031 }
1032 }
1033
1034 if (props_active->layer_collection_exclude) {
1036 layer_collection_ptr, props->layer_collection_exclude);
1037
1038 if (!props_active->layer_collection_exclude) {
1039 props_active->collection_hide_viewport = false;
1040 props_active->collection_hide_select = false;
1041 props_active->collection_hide_render = false;
1042 props_active->layer_collection_hide_viewport = false;
1043 props_active->layer_collection_holdout = false;
1044 props_active->layer_collection_indirect_only = false;
1045 }
1046 }
1047}
1048
1050 TreeElement *te,
1051 PointerRNA *collection_ptr,
1052 PointerRNA *layer_collection_ptr,
1053 RestrictProperties *props,
1054 RestrictPropertiesActive *props_active)
1055{
1056 TreeStoreElem *tselem = TREESTORE(te);
1057 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1058 static_cast<LayerCollection *>(te->directdata) :
1059 nullptr;
1061
1062 if (collection->flag & COLLECTION_IS_MASTER) {
1063 return false;
1064 }
1065
1066 /* Create the PointerRNA. */
1067 *collection_ptr = RNA_id_pointer_create(&collection->id);
1068 if (layer_collection != nullptr) {
1069 *layer_collection_ptr = RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection);
1070 }
1071
1072 /* Update the restriction column values for the collection children. */
1073 if (layer_collection) {
1075 layer_collection_ptr, collection_ptr, props, props_active);
1076 }
1077 else {
1078 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1079 }
1080 return true;
1081}
1082
1084 Scene *scene,
1085 ViewLayer *view_layer,
1086 ARegion *region,
1087 SpaceOutliner *space_outliner,
1088 ListBase *lb,
1089 RestrictPropertiesActive props_active_parent)
1090{
1091 /* Get RNA properties (once for speed). */
1092 static RestrictProperties props = {false};
1093 if (!props.initialized) {
1094 props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport");
1095 props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
1096 props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
1097 props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport");
1099 "hide_viewport");
1100 props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
1101 props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
1102 props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection,
1103 "exclude");
1104 props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection,
1105 "holdout");
1107 "indirect_only");
1109 "hide_viewport");
1110 props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
1111 props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
1112
1113 props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
1114
1115 props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide");
1116
1117 props.initialized = true;
1118 }
1119
1120 struct {
1121 int enable;
1122 int select;
1123 int hide;
1124 int viewport;
1125 int render;
1126 int indirect_only;
1127 int holdout;
1128 } restrict_offsets = {0};
1129 int restrict_column_offset = 0;
1130
1131 /* This will determine the order of drawing from RIGHT to LEFT. */
1132 if (space_outliner->outlinevis == SO_VIEW_LAYER) {
1133 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1134 restrict_offsets.indirect_only = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1135 }
1136 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1137 restrict_offsets.holdout = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1138 }
1139 }
1140 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1141 restrict_offsets.render = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1142 }
1143 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1144 restrict_offsets.viewport = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1145 }
1146 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1147 restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1148 }
1149 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1150 restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1151 }
1152 if (space_outliner->outlinevis == SO_VIEW_LAYER &&
1153 space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)
1154 {
1155 restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1156 }
1157
1158 BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
1159 outliner_right_columns_width(space_outliner));
1160
1161 /* Create buttons. */
1162 uiBut *bt;
1163
1164 LISTBASE_FOREACH (TreeElement *, te, lb) {
1165 TreeStoreElem *tselem = TREESTORE(te);
1166 RestrictPropertiesActive props_active = props_active_parent;
1167
1168 if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
1169 if (tselem->type == TSE_R_LAYER &&
1170 ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER))
1171 {
1172 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1173 /* View layer render toggle. */
1174 ViewLayer *layer = static_cast<ViewLayer *>(te->directdata);
1175
1176 bt = uiDefIconButBitS(block,
1179 0,
1180 ICON_RESTRICT_RENDER_OFF,
1181 int(region->v2d.cur.xmax - restrict_offsets.render),
1182 te->ys,
1183 UI_UNIT_X,
1184 UI_UNIT_Y,
1185 &layer->flag,
1186 0,
1187 0,
1188 TIP_("Use view layer for rendering"));
1189 UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
1192 }
1193 }
1194 else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) &&
1195 (te->flag & TE_CHILD_NOT_IN_COLLECTION))
1196 {
1197 /* Don't show restrict columns for children that are not directly inside the collection. */
1198 }
1199 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1200 Object *ob = (Object *)tselem->id;
1202
1203 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1204 BKE_view_layer_synced_ensure(scene, view_layer);
1205 Base *base = (te->directdata) ? (Base *)te->directdata :
1206 BKE_view_layer_base_find(view_layer, ob);
1207 if (base) {
1208 PointerRNA base_ptr = RNA_pointer_create(&scene->id, &RNA_ObjectBase, base);
1209 bt = uiDefIconButR_prop(block,
1211 0,
1212 ICON_NONE,
1213 int(region->v2d.cur.xmax - restrict_offsets.hide),
1214 te->ys,
1215 UI_UNIT_X,
1216 UI_UNIT_Y,
1217 &base_ptr,
1218 props.base_hide_viewport,
1219 -1,
1220 0,
1221 0,
1222 TIP_("Temporarily hide in viewport\n"
1223 " \u2022 Shift to set children"));
1225 bt, outliner__base_set_flag_recursive_fn, base, (void *)"hide_viewport");
1227 if (!props_active.base_hide_viewport) {
1229 }
1230 }
1231 }
1232
1233 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1234 bt = uiDefIconButR_prop(block,
1236 0,
1237 ICON_NONE,
1238 int(region->v2d.cur.xmax - restrict_offsets.select),
1239 te->ys,
1240 UI_UNIT_X,
1241 UI_UNIT_Y,
1242 &ptr,
1243 props.object_hide_select,
1244 -1,
1245 0,
1246 0,
1247 TIP_("Disable selection in viewport\n"
1248 " \u2022 Shift to set children"));
1249 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_select");
1251 if (!props_active.object_hide_select) {
1253 }
1254 }
1255
1256 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1257 bt = uiDefIconButR_prop(block,
1259 0,
1260 ICON_NONE,
1261 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1262 te->ys,
1263 UI_UNIT_X,
1264 UI_UNIT_Y,
1265 &ptr,
1267 -1,
1268 0,
1269 0,
1270 TIP_("Globally disable in viewports\n"
1271 " \u2022 Shift to set children"));
1272 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (void *)"hide_viewport");
1274 if (!props_active.object_hide_viewport) {
1276 }
1277 }
1278
1279 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1280 bt = uiDefIconButR_prop(block,
1282 0,
1283 ICON_NONE,
1284 int(region->v2d.cur.xmax - restrict_offsets.render),
1285 te->ys,
1286 UI_UNIT_X,
1287 UI_UNIT_Y,
1288 &ptr,
1289 props.object_hide_render,
1290 -1,
1291 0,
1292 0,
1293 TIP_("Globally disable in renders\n"
1294 " \u2022 Shift to set children"));
1295 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_render");
1297 if (!props_active.object_hide_render) {
1299 }
1300 }
1301 }
1302 else if (tselem->type == TSE_CONSTRAINT) {
1303 bConstraint *con = (bConstraint *)te->directdata;
1304
1305 PointerRNA ptr = RNA_pointer_create(tselem->id, &RNA_Constraint, con);
1306
1307 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1308 bt = uiDefIconButR_prop(block,
1310 0,
1311 ICON_NONE,
1312 int(region->v2d.cur.xmax - restrict_offsets.hide),
1313 te->ys,
1314 UI_UNIT_X,
1315 UI_UNIT_Y,
1316 &ptr,
1317 props.constraint_enable,
1318 -1,
1319 0,
1320 0,
1321 nullptr);
1323 if (!props_active.constraint_enable) {
1325 }
1326 }
1327 }
1328 else if (tselem->type == TSE_MODIFIER) {
1329 ModifierData *md = (ModifierData *)te->directdata;
1330
1331 PointerRNA ptr = RNA_pointer_create(tselem->id, &RNA_Modifier, md);
1332
1333 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1334 bt = uiDefIconButR_prop(block,
1336 0,
1337 ICON_NONE,
1338 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1339 te->ys,
1340 UI_UNIT_X,
1341 UI_UNIT_Y,
1342 &ptr,
1344 -1,
1345 0,
1346 0,
1347 nullptr);
1349 if (!props_active.modifier_show_viewport) {
1351 }
1352 }
1353
1354 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1355 bt = uiDefIconButR_prop(block,
1357 0,
1358 ICON_NONE,
1359 int(region->v2d.cur.xmax - restrict_offsets.render),
1360 te->ys,
1361 UI_UNIT_X,
1362 UI_UNIT_Y,
1363 &ptr,
1365 -1,
1366 0,
1367 0,
1368 nullptr);
1370 if (!props_active.modifier_show_render) {
1372 }
1373 }
1374 }
1375 else if (tselem->type == TSE_POSE_CHANNEL) {
1376 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
1377 Bone *bone = pchan->bone;
1378 Object *ob = (Object *)tselem->id;
1379 bArmature *arm = static_cast<bArmature *>(ob->data);
1380
1381 PointerRNA ptr = RNA_pointer_create(&arm->id, &RNA_Bone, bone);
1382
1383 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1384 bt = uiDefIconButR_prop(block,
1386 0,
1387 ICON_NONE,
1388 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1389 te->ys,
1390 UI_UNIT_X,
1391 UI_UNIT_Y,
1392 &ptr,
1393 props.bone_hide_viewport,
1394 -1,
1395 0,
1396 0,
1397 TIP_("Restrict visibility in the 3D View\n"
1398 " \u2022 Shift to set children"));
1402 }
1403
1404 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1405 bt = uiDefIconButBitI(block,
1408 0,
1409 ICON_RESTRICT_SELECT_OFF,
1410 int(region->v2d.cur.xmax - restrict_offsets.select),
1411 te->ys,
1412 UI_UNIT_X,
1413 UI_UNIT_Y,
1414 &(bone->flag),
1415 0,
1416 0,
1417 TIP_("Restrict selection in the 3D View\n"
1418 " \u2022 Shift to set children"));
1422 }
1423 }
1424 else if (tselem->type == TSE_EBONE) {
1425 bArmature *arm = (bArmature *)tselem->id;
1426 EditBone *ebone = (EditBone *)te->directdata;
1427
1428 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1429 bt = uiDefIconButBitI(block,
1432 0,
1433 ICON_RESTRICT_VIEW_OFF,
1434 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1435 te->ys,
1436 UI_UNIT_X,
1437 UI_UNIT_Y,
1438 &(ebone->flag),
1439 0,
1440 0,
1441 TIP_("Restrict visibility in the 3D View\n"
1442 " \u2022 Shift to set children"));
1446 }
1447
1448 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1449 bt = uiDefIconButBitI(block,
1452 0,
1453 ICON_RESTRICT_SELECT_OFF,
1454 int(region->v2d.cur.xmax - restrict_offsets.select),
1455 te->ys,
1456 UI_UNIT_X,
1457 UI_UNIT_Y,
1458 &(ebone->flag),
1459 0,
1460 0,
1461 TIP_("Restrict selection in the 3D View\n"
1462 " \u2022 Shift to set children"));
1466 }
1467 }
1468 else if (tselem->type == TSE_GP_LAYER) {
1469 ID *id = tselem->id;
1470 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
1471
1472 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1473 bt = uiDefIconButBitS(block,
1476 0,
1477 ICON_HIDE_OFF,
1478 int(region->v2d.cur.xmax - restrict_offsets.hide),
1479 te->ys,
1480 UI_UNIT_X,
1481 UI_UNIT_Y,
1482 &gpl->flag,
1483 0,
1484 0,
1485 TIP_("Restrict visibility in the 3D View"));
1489 }
1490
1491 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1492 bt = uiDefIconButBitS(block,
1495 0,
1496 ICON_UNLOCKED,
1497 int(region->v2d.cur.xmax - restrict_offsets.select),
1498 te->ys,
1499 UI_UNIT_X,
1500 UI_UNIT_Y,
1501 &gpl->flag,
1502 0,
1503 0,
1504 TIP_("Restrict editing of strokes and keyframes in this layer"));
1507 }
1508 }
1509 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
1513 PropertyRNA *hide_prop;
1514 if (node.is_layer()) {
1515 ptr = RNA_pointer_create(tselem->id, &RNA_GreasePencilLayer, &node);
1516 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayer, "hide");
1517 }
1518 else if (node.is_group()) {
1519 ptr = RNA_pointer_create(tselem->id, &RNA_GreasePencilLayerGroup, &node);
1520 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayerGroup, "hide");
1521 }
1522
1523 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1524 bt = uiDefIconButR_prop(block,
1526 0,
1527 0,
1528 int(region->v2d.cur.xmax - restrict_offsets.hide),
1529 te->ys,
1530 UI_UNIT_X,
1531 UI_UNIT_Y,
1532 &ptr,
1533 hide_prop,
1534 -1,
1535 0,
1536 0,
1537 nullptr);
1539 if (node.parent_group() && node.parent_group()->is_visible()) {
1541 }
1542 }
1543 }
1545 PointerRNA collection_ptr;
1546 PointerRNA layer_collection_ptr;
1547
1549 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active))
1550 {
1551
1552 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1553 static_cast<LayerCollection *>(te->directdata) :
1554 nullptr;
1556
1557 if (layer_collection != nullptr) {
1558 if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
1559 bt = uiDefIconButR_prop(block,
1561 0,
1562 ICON_NONE,
1563 int(region->v2d.cur.xmax) - restrict_offsets.enable,
1564 te->ys,
1565 UI_UNIT_X,
1566 UI_UNIT_Y,
1567 &layer_collection_ptr,
1569 -1,
1570 0,
1571 0,
1572 nullptr);
1574 }
1575
1576 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1577 bt = uiDefIconButR_prop(block,
1579 0,
1580 ICON_NONE,
1581 int(region->v2d.cur.xmax - restrict_offsets.hide),
1582 te->ys,
1583 UI_UNIT_X,
1584 UI_UNIT_Y,
1585 &layer_collection_ptr,
1587 -1,
1588 0,
1589 0,
1590 TIP_("Temporarily hide in viewport\n"
1591 " \u2022 Ctrl to isolate collection\n"
1592 " \u2022 Shift to set inside collections and objects"));
1593 UI_but_func_set(bt,
1595 layer_collection,
1596 (char *)"hide_viewport");
1598 if (!props_active.layer_collection_hide_viewport) {
1600 }
1601 }
1602
1603 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1604 bt = uiDefIconButR_prop(block,
1606 0,
1607 ICON_NONE,
1608 int(region->v2d.cur.xmax - restrict_offsets.holdout),
1609 te->ys,
1610 UI_UNIT_X,
1611 UI_UNIT_Y,
1612 &layer_collection_ptr,
1614 -1,
1615 0,
1616 0,
1617 TIP_("Mask out objects in collection from view layer\n"
1618 " \u2022 Ctrl to isolate collection\n"
1619 " \u2022 Shift to set inside collections"));
1620 UI_but_func_set(bt,
1622 layer_collection,
1623 (char *)"holdout");
1625 if (!props_active.layer_collection_holdout) {
1627 }
1628 }
1629
1630 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1631 bt = uiDefIconButR_prop(
1632 block,
1634 0,
1635 ICON_NONE,
1636 int(region->v2d.cur.xmax - restrict_offsets.indirect_only),
1637 te->ys,
1638 UI_UNIT_X,
1639 UI_UNIT_Y,
1640 &layer_collection_ptr,
1642 -1,
1643 0,
1644 0,
1645 TIP_("Objects in collection only contribute indirectly (through shadows and "
1646 "reflections) in the view layer\n"
1647 " \u2022 Ctrl to isolate collection\n"
1648 " \u2022 Shift to set inside collections"));
1649 UI_but_func_set(bt,
1651 layer_collection,
1652 (char *)"indirect_only");
1654 if (props_active.layer_collection_holdout ||
1655 !props_active.layer_collection_indirect_only)
1656 {
1658 }
1659 }
1660 }
1661
1662 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1663 bt = uiDefIconButR_prop(block,
1665 0,
1666 ICON_NONE,
1667 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1668 te->ys,
1669 UI_UNIT_X,
1670 UI_UNIT_Y,
1671 &collection_ptr,
1673 -1,
1674 0,
1675 0,
1676 TIP_("Globally disable in viewports\n"
1677 " \u2022 Ctrl to isolate collection\n"
1678 " \u2022 Shift to set inside collections and objects"));
1679 if (layer_collection != nullptr) {
1680 UI_but_func_set(bt,
1682 layer_collection,
1683 (char *)"hide_viewport");
1684 }
1685 else {
1686 UI_but_func_set(bt,
1688 collection,
1689 (char *)"hide_viewport");
1690 }
1692 if (!props_active.collection_hide_viewport) {
1694 }
1695 }
1696
1697 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1698 bt = uiDefIconButR_prop(block,
1700 0,
1701 ICON_NONE,
1702 int(region->v2d.cur.xmax - restrict_offsets.render),
1703 te->ys,
1704 UI_UNIT_X,
1705 UI_UNIT_Y,
1706 &collection_ptr,
1708 -1,
1709 0,
1710 0,
1711 TIP_("Globally disable in renders\n"
1712 " \u2022 Ctrl to isolate collection\n"
1713 " \u2022 Shift to set inside collections and objects"));
1714 if (layer_collection != nullptr) {
1715 UI_but_func_set(bt,
1717 layer_collection,
1718 (char *)"hide_render");
1719 }
1720 else {
1722 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_render");
1723 }
1725 if (!props_active.collection_hide_render) {
1727 }
1728 }
1729
1730 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1731 bt = uiDefIconButR_prop(block,
1733 0,
1734 ICON_NONE,
1735 int(region->v2d.cur.xmax - restrict_offsets.select),
1736 te->ys,
1737 UI_UNIT_X,
1738 UI_UNIT_Y,
1739 &collection_ptr,
1741 -1,
1742 0,
1743 0,
1744 TIP_("Disable selection in viewport\n"
1745 " \u2022 Ctrl to isolate collection\n"
1746 " \u2022 Shift to set inside collections and objects"));
1747 if (layer_collection != nullptr) {
1748 UI_but_func_set(bt,
1750 layer_collection,
1751 (char *)"hide_select");
1752 }
1753 else {
1755 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_select");
1756 }
1758 if (!props_active.collection_hide_select) {
1760 }
1761 }
1762 }
1763 }
1764 }
1766 PointerRNA collection_ptr;
1767 PointerRNA layer_collection_ptr;
1769 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active);
1770 }
1771
1772 if (TSELEM_OPEN(tselem, space_outliner)) {
1774 block, scene, view_layer, region, space_outliner, &te->subtree, props_active);
1775 }
1776 }
1777}
1778
1780 const ARegion *region,
1781 const SpaceOutliner *space_outliner)
1782{
1783 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
1784 if (!outliner_is_element_in_view(te, &region->v2d)) {
1785 return;
1786 }
1787
1788 const TreeStoreElem *tselem = TREESTORE(te);
1789 ID *id = tselem->id;
1790
1791 if (tselem->type != TSE_SOME_ID || id->tag & ID_TAG_EXTRAUSER) {
1792 return;
1793 }
1794
1795 uiBut *bt;
1796 const char *tip = nullptr;
1797 const int real_users = id->us - ID_FAKE_USERS(id);
1798 const bool has_fake_user = id->flag & ID_FLAG_FAKEUSER;
1799 const bool is_linked = ID_IS_LINKED(id);
1800 const bool is_object = GS(id->name) == ID_OB;
1801 char overlay[5];
1802 BLI_str_format_integer_unit(overlay, id->us);
1803
1804 if (is_object) {
1805 bt = uiDefBut(block,
1807 0,
1808 overlay,
1809 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1810 te->ys,
1811 UI_UNIT_X,
1812 UI_UNIT_Y,
1813 nullptr,
1814 0.0,
1815 0.0,
1816 TIP_("Number of users"));
1817 }
1818 else {
1819
1820 if (has_fake_user) {
1821 tip = is_linked ? TIP_("Item is protected from deletion") :
1822 TIP_("Click to remove protection from deletion");
1823 }
1824 else {
1825 if (real_users) {
1826 tip = is_linked ? TIP_("Item is not protected from deletion") :
1827 TIP_("Click to add protection from deletion");
1828 }
1829 else {
1830 tip = is_linked ?
1831 TIP_("Item has no users and will be removed") :
1832 TIP_("Item has no users and will be removed.\nClick to protect from deletion");
1833 }
1834 }
1835
1836 bt = uiDefIconButBitS(block,
1839 1,
1840 ICON_FAKE_USER_OFF,
1841 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1842 te->ys,
1843 UI_UNIT_X,
1844 UI_UNIT_Y,
1845 &id->flag,
1846 0,
1847 0,
1848 tip);
1849
1850 if (is_linked) {
1852 }
1853 else {
1855 /* Allow _inaccurate_ dragging over multiple toggles. */
1857 }
1858
1859 if (!real_users && !has_fake_user) {
1860 uchar overlay_color[4];
1861 UI_GetThemeColor4ubv(TH_REDALERT, overlay_color);
1862 UI_but_icon_indicator_color_set(bt, overlay_color);
1863 }
1864 UI_but_icon_indicator_set(bt, overlay);
1865 }
1866 });
1867}
1868
1870 const ARegion *region,
1871 const SpaceOutliner *space_outliner,
1872 const ListBase *lb,
1873 const int x)
1874{
1875 const float pad_x = 2.0f * UI_SCALE_FAC;
1876 const float pad_y = 0.5f * U.pixelsize;
1877 const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x);
1878 const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y);
1879
1880 LISTBASE_FOREACH (const TreeElement *, te, lb) {
1881 const TreeStoreElem *tselem = TREESTORE(te);
1882 if (TSELEM_OPEN(tselem, space_outliner)) {
1883 outliner_draw_overrides_rna_buts(block, region, space_outliner, &te->subtree, x);
1884 }
1885
1886 if (!outliner_is_element_in_view(te, &region->v2d)) {
1887 continue;
1888 }
1890 te);
1891 if (!override_elem) {
1892 continue;
1893 }
1894
1895 if (!override_elem->is_rna_path_valid) {
1896 uiBut *but = uiDefBut(block,
1898 0,
1899 override_elem->rna_path,
1900 x + pad_x,
1901 te->ys + pad_y,
1902 item_max_width,
1903 item_height,
1904 nullptr,
1905 0.0f,
1906 0.0f,
1907 "");
1909 continue;
1910 }
1911
1912 if (const TreeElementOverridesPropertyOperation *override_op_elem =
1914 {
1915 StringRefNull op_label = override_op_elem->get_override_operation_label();
1916 if (!op_label.is_empty()) {
1917 uiDefBut(block,
1919 0,
1920 op_label,
1921 x + pad_x,
1922 te->ys + pad_y,
1923 item_max_width,
1924 item_height,
1925 nullptr,
1926 0,
1927 0,
1928 "");
1929 continue;
1930 }
1931 }
1932
1933 PointerRNA *ptr = &override_elem->override_rna_ptr;
1934 PropertyRNA *prop = &override_elem->override_rna_prop;
1935 const PropertyType prop_type = RNA_property_type(prop);
1936
1937 uiBut *auto_but = uiDefAutoButR(block,
1938 ptr,
1939 prop,
1940 -1,
1941 (prop_type == PROP_ENUM) ? nullptr : "",
1942 ICON_NONE,
1943 x + pad_x,
1944 te->ys + pad_y,
1945 item_max_width,
1946 item_height);
1947 /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons
1948 * need to be handled. */
1949 if (auto_but) {
1950 continue;
1951 }
1952
1953 if (!auto_but) {
1954 /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension
1955 * arrays? */
1957 block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height);
1958 }
1959 }
1960}
1961
1963{
1964 const PointerRNA *idptr_a = UI_but_context_ptr_get(a, "id", &RNA_ID);
1965 const PointerRNA *idptr_b = UI_but_context_ptr_get(b, "id", &RNA_ID);
1966 if (!idptr_a || !idptr_b) {
1967 return false;
1968 }
1969 const ID *id_a = (const ID *)idptr_a->data;
1970 const ID *id_b = (const ID *)idptr_b->data;
1971
1972 /* Using session UID to compare is safer than using the pointer. */
1973 return id_a->session_uid == id_b->session_uid;
1974}
1975
1977 uiBlock *block,
1978 const ARegion *region,
1979 const SpaceOutliner *space_outliner,
1980 const ListBase *lb,
1981 const int x)
1982{
1983 LISTBASE_FOREACH (const TreeElement *, te, lb) {
1984 const TreeStoreElem *tselem = TREESTORE(te);
1985 if (TSELEM_OPEN(tselem, space_outliner)) {
1986 outliner_draw_overrides_restrictbuts(bmain, block, region, space_outliner, &te->subtree, x);
1987 }
1988
1989 if (!outliner_is_element_in_view(te, &region->v2d)) {
1990 continue;
1991 }
1993 if (!te_id) {
1994 continue;
1995 }
1996
1997 ID &id = te_id->get_ID();
1998 if (ID_IS_LINKED(&id)) {
1999 continue;
2000 }
2001 if (!ID_IS_OVERRIDE_LIBRARY(&id)) {
2002 /* Some items may not be liboverrides, e.g. the root item for all linked libraries (see
2003 * #TreeDisplayOverrideLibraryHierarchies::build_tree). */
2004 continue;
2005 }
2006
2007 const bool is_system_override = BKE_lib_override_library_is_system_defined(bmain, &id);
2008 const BIFIconID icon = is_system_override ? ICON_LIBRARY_DATA_OVERRIDE_NONEDITABLE :
2009 ICON_LIBRARY_DATA_OVERRIDE;
2010 uiBut *but = uiDefIconButO(block,
2012 "ED_OT_lib_id_override_editable_toggle",
2014 icon,
2015 x,
2016 te->ys,
2017 UI_UNIT_X,
2018 UI_UNIT_Y,
2019 "");
2020 PointerRNA idptr = RNA_id_pointer_create(&id);
2021 UI_but_context_ptr_set(block, but, "id", &idptr);
2024 }
2025}
2026
2027static void outliner_draw_separator(ARegion *region, const int x)
2028{
2029 View2D *v2d = &region->v2d;
2030
2031 GPU_line_width(1.0f);
2032
2036
2038
2039 immVertex2f(pos, x, v2d->cur.ymax);
2040 immVertex2f(pos, x, v2d->cur.ymin);
2041
2042 immEnd();
2043
2045}
2046
2048 ARegion *region,
2049 SpaceOutliner *space_outliner,
2050 int sizex)
2051{
2053 PropertyRNA *prop;
2054
2055 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2056 TreeStoreElem *tselem = TREESTORE(te);
2057
2058 if (!outliner_is_element_in_view(te, &region->v2d)) {
2059 return;
2060 }
2061
2063 ptr = te_rna_prop->get_pointer_rna();
2064 prop = te_rna_prop->get_property_rna();
2065
2066 if (!TSELEM_OPEN(tselem, space_outliner)) {
2067 if (RNA_property_type(prop) == PROP_POINTER) {
2068 uiBut *but = uiDefAutoButR(block,
2069 &ptr,
2070 prop,
2071 -1,
2072 "",
2073 ICON_NONE,
2074 sizex,
2075 te->ys,
2077 UI_UNIT_Y - 1);
2079 }
2080 else if (RNA_property_type(prop) == PROP_ENUM) {
2081 uiDefAutoButR(block,
2082 &ptr,
2083 prop,
2084 -1,
2085 nullptr,
2086 ICON_NONE,
2087 sizex,
2088 te->ys,
2090 UI_UNIT_Y - 1);
2091 }
2092 else {
2093 uiDefAutoButR(block,
2094 &ptr,
2095 prop,
2096 -1,
2097 "",
2098 ICON_NONE,
2099 sizex,
2100 te->ys,
2102 UI_UNIT_Y - 1);
2103 }
2104 }
2105 }
2106 else if (TreeElementRNAArrayElement *te_rna_array_elem =
2108 {
2109 ptr = te_rna_array_elem->get_pointer_rna();
2110 prop = te_rna_array_elem->get_property_rna();
2111
2112 uiDefAutoButR(block,
2113 &ptr,
2114 prop,
2115 te->index,
2116 "",
2117 ICON_NONE,
2118 sizex,
2119 te->ys,
2121 UI_UNIT_Y - 1);
2122 }
2123 });
2124}
2125
2126static void outliner_buttons(const bContext *C,
2127 uiBlock *block,
2128 ARegion *region,
2129 const float restrict_column_width,
2130 TreeElement *te)
2131{
2132 uiBut *bt;
2133 TreeStoreElem *tselem;
2134 int spx, dx, len;
2135
2136 tselem = TREESTORE(te);
2137
2138 BLI_assert(tselem->flag & TSE_TEXTBUT);
2139 /* If we add support to rename Sequence, need change this. */
2140
2141 if (tselem->type == TSE_EBONE) {
2142 len = sizeof(EditBone::name);
2143 }
2144 else if (tselem->type == TSE_MODIFIER) {
2145 len = sizeof(ModifierData::name);
2146 }
2147 else if (tselem->id && GS(tselem->id->name) == ID_LI) {
2148 len = sizeof(Library::filepath);
2149 }
2150 else {
2151 len = MAX_ID_NAME - 2;
2152 }
2153
2154 spx = te->xs + 1.8f * UI_UNIT_X;
2155 dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X);
2156
2157 bt = uiDefBut(block,
2160 "",
2161 spx,
2162 te->ys,
2163 dx,
2164 UI_UNIT_Y - 1,
2165 (void *)te->name,
2166 1.0,
2167 float(len),
2168 "");
2169 /* Handle undo through the #template_id_cb set below. Default undo handling from the button
2170 * code (see #ui_apply_but_undo) would not work here, as the new name is not yet applied to the
2171 * ID. */
2174
2175 /* Returns false if button got removed. */
2176 if (false == UI_but_active_only(C, region, block, bt)) {
2177 tselem->flag &= ~TSE_TEXTBUT;
2178
2179 /* Bad! (notifier within draw) without this, we don't get a refresh. */
2181 }
2182}
2183
2184static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void * /*arg2*/)
2185{
2186 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2187 TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin;
2188 TreeViewContext tvc;
2190
2191 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
2192 if (!te) {
2193 return;
2194 }
2195
2196 /* Check that the item is actually an object. */
2197 BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
2198
2199 Object *ob = (Object *)tselem->id;
2200 const bool object_data_shared = (ob->data == tvc.obact->data);
2201
2202 wmWindow *win = CTX_wm_window(C);
2203 const bool do_extend = (win->eventstate->modifier & KM_CTRL) && !object_data_shared;
2204 outliner_item_mode_toggle(C, &tvc, te, do_extend);
2205}
2206
2207/* Draw icons for adding and removing objects from the current interaction mode. */
2209 TreeViewContext *tvc,
2210 TreeElement *te,
2211 const bool lock_object_modes)
2212{
2213 TreeStoreElem *tselem = TREESTORE(te);
2214 if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
2215 return;
2216 }
2217
2218 Object *ob = (Object *)tselem->id;
2219 Object *ob_active = tvc->obact;
2220
2221 /* Not all objects support particle systems. */
2222 if (ob_active->mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) {
2223 return;
2224 }
2225
2226 /* Only for objects with the same type. */
2227 if (ob->type != ob_active->type) {
2228 return;
2229 }
2230
2231 if (ob->mode == OB_MODE_OBJECT && BKE_object_is_in_editmode(ob)) {
2232 /* Another object has our (shared) data in edit mode, so nothing we can change. */
2233 uiBut *but = uiDefIconBut(block,
2235 0,
2236 UI_icon_from_object_mode(ob_active->mode),
2237 0,
2238 te->ys,
2239 UI_UNIT_X,
2240 UI_UNIT_Y,
2241 nullptr,
2242 0.0,
2243 0.0,
2244 TIP_("Another object has this shared data in edit mode"));
2246 return;
2247 }
2248
2249 bool draw_active_icon = ob->mode == ob_active->mode;
2250
2251 /* When not locking object modes, objects can remain in non-object modes. For modes that do not
2252 * allow multi-object editing, these other objects should still show be viewed as not in the
2253 * mode. Otherwise multiple objects show the same mode icon in the outliner even though only
2254 * one object is actually editable in the mode. */
2255 if (!lock_object_modes && ob != ob_active && !(tvc->ob_edit || tvc->ob_pose)) {
2256 draw_active_icon = false;
2257 }
2258
2259 const bool object_data_shared = (ob->data == ob_active->data);
2260 draw_active_icon = draw_active_icon || object_data_shared;
2261
2262 int icon;
2263 const char *tip;
2264 if (draw_active_icon) {
2265 icon = UI_icon_from_object_mode(ob_active->mode);
2266 tip = object_data_shared ? TIP_("Change the object in the current mode") :
2267 TIP_("Remove from the current mode");
2268 }
2269 else {
2270 icon = ICON_DOT;
2271 tip = TIP_(
2272 "Change the object in the current mode\n"
2273 " \u2022 Ctrl to add to the current mode");
2274 }
2276 uiBut *but = uiDefIconBut(block,
2278 0,
2279 icon,
2280 0,
2281 te->ys,
2282 UI_UNIT_X,
2283 UI_UNIT_Y,
2284 nullptr,
2285 0.0,
2286 0.0,
2287 tip);
2288 UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
2290 /* Mode toggling handles its own undo state because undo steps need to be grouped. */
2292
2293 if (!ID_IS_EDITABLE(&ob->id) ||
2296 {
2297 UI_but_disable(but, "Can't edit library or non-editable override data");
2298 }
2299}
2300
2302 TreeViewContext *tvc,
2303 SpaceOutliner *space_outliner)
2304{
2305 const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
2306
2307 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2308 if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) {
2309 outliner_draw_mode_column_toggle(block, tvc, te, lock_object_modes);
2310 }
2311 });
2312}
2313
2315{
2316 LISTBASE_FOREACH (const TreeElement *, sub_te, &parent_te->subtree) {
2318 StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2319
2320 if (!warning_msg.is_empty()) {
2321 return warning_msg;
2322 }
2323
2325 if (!warning_msg.is_empty()) {
2326 return warning_msg;
2327 }
2328 }
2329
2330 return "";
2331}
2332
2334 const TreeElement *te)
2335{
2337 const StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2338
2339 if (!warning_msg.is_empty()) {
2340 return warning_msg;
2341 }
2342
2343 /* If given element has no warning, recursively try to display the first sub-element's warning.
2344 */
2345 if (!TSELEM_OPEN(te->store_elem, &space_outliner)) {
2347 }
2348
2349 return "";
2350}
2351
2353 const SpaceOutliner *space_outliner,
2354 StringRefNull warning_msg,
2355 const bool use_mode_column,
2356 const int te_ys)
2357{
2358 /* Move the warnings a unit left in view layer mode. */
2359 const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
2360 UI_UNIT_X :
2361 0;
2362
2364 uiBut *but = uiDefIconBut(block,
2366 0,
2367 ICON_ERROR,
2368 mode_column_offset,
2369 te_ys,
2370 UI_UNIT_X,
2371 UI_UNIT_Y,
2372 nullptr,
2373 0.0,
2374 0.0,
2375 warning_msg.c_str());
2376 /* No need for undo here, this is a pure info widget. */
2378}
2379
2381 const SpaceOutliner *space_outliner,
2382 const bool use_mode_column)
2383{
2384 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
2385 /* Get warning for this element, or if there is none and the element is collapsed, the first
2386 * warning in the collapsed sub-tree. */
2387 StringRefNull warning_msg = outliner_draw_get_warning_tree_element(*space_outliner, te);
2388
2389 if (!warning_msg.is_empty()) {
2391 block, space_outliner, warning_msg, use_mode_column, te->ys);
2392 }
2393 });
2394}
2395
2398/* -------------------------------------------------------------------- */
2403{
2404 if (GS(id->name) == ID_OB) {
2405 const Object *ob = (Object *)id;
2406 switch (ob->type) {
2407 case OB_LAMP:
2408 return ICON_OUTLINER_OB_LIGHT;
2409 case OB_MESH:
2410 return ICON_OUTLINER_OB_MESH;
2411 case OB_CAMERA:
2412 return ICON_OUTLINER_OB_CAMERA;
2413 case OB_CURVES_LEGACY:
2414 return ICON_OUTLINER_OB_CURVE;
2415 case OB_MBALL:
2416 return ICON_OUTLINER_OB_META;
2417 case OB_LATTICE:
2418 return ICON_OUTLINER_OB_LATTICE;
2419 case OB_ARMATURE:
2420 return ICON_OUTLINER_OB_ARMATURE;
2421 case OB_FONT:
2422 return ICON_OUTLINER_OB_FONT;
2423 case OB_SURF:
2424 return ICON_OUTLINER_OB_SURFACE;
2425 case OB_SPEAKER:
2426 return ICON_OUTLINER_OB_SPEAKER;
2427 case OB_LIGHTPROBE:
2428 return ICON_OUTLINER_OB_LIGHTPROBE;
2429 case OB_CURVES:
2430 return ICON_OUTLINER_OB_CURVES;
2431 case OB_POINTCLOUD:
2432 return ICON_OUTLINER_OB_POINTCLOUD;
2433 case OB_VOLUME:
2434 return ICON_OUTLINER_OB_VOLUME;
2435 case OB_EMPTY:
2437 return ICON_OUTLINER_OB_GROUP_INSTANCE;
2438 }
2439 else if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
2440 return ICON_OUTLINER_OB_IMAGE;
2441 }
2442 else if (ob->pd && ob->pd->forcefield) {
2443 return ICON_OUTLINER_OB_FORCE_FIELD;
2444 }
2445 else {
2446 return ICON_OUTLINER_OB_EMPTY;
2447 }
2448 case OB_GPENCIL_LEGACY:
2449 return ICON_OUTLINER_OB_GREASEPENCIL;
2450 case OB_GREASE_PENCIL:
2451 return ICON_OUTLINER_OB_GREASEPENCIL;
2452 }
2453
2454 return ICON_NONE;
2455 }
2456
2457 /* TODO(sergey): Casting to short here just to handle ID_NLA which is
2458 * NOT inside of IDType enum.
2459 */
2460 switch (short(GS(id->name))) {
2461 case ID_SCE:
2462 return ICON_SCENE_DATA;
2463 case ID_ME:
2464 return ICON_OUTLINER_DATA_MESH;
2465 case ID_CU_LEGACY: {
2466 const Curve *cu = (Curve *)id;
2467 const short obtype = BKE_curve_type_get(cu);
2468
2469 switch (obtype) {
2470 case OB_FONT:
2471 return ICON_OUTLINER_DATA_FONT;
2472 case OB_SURF:
2473 return ICON_OUTLINER_DATA_SURFACE;
2474 default:
2475 return ICON_OUTLINER_DATA_CURVE;
2476 }
2477 break;
2478 }
2479 case ID_MB:
2480 return ICON_OUTLINER_DATA_META;
2481 case ID_LT:
2482 return ICON_OUTLINER_DATA_LATTICE;
2483 case ID_LA: {
2484 const Light *la = (Light *)id;
2485 switch (la->type) {
2486 case LA_LOCAL:
2487 return ICON_LIGHT_POINT;
2488 case LA_SUN:
2489 return ICON_LIGHT_SUN;
2490 case LA_SPOT:
2491 return ICON_LIGHT_SPOT;
2492 case LA_AREA:
2493 return ICON_LIGHT_AREA;
2494 default:
2495 return ICON_OUTLINER_DATA_LIGHT;
2496 }
2497 }
2498 case ID_MA:
2499 return ICON_MATERIAL_DATA;
2500 case ID_TE:
2501 return ICON_TEXTURE_DATA;
2502 case ID_IM:
2503 return ICON_IMAGE_DATA;
2504 case ID_SPK:
2505 case ID_SO:
2506 return ICON_OUTLINER_DATA_SPEAKER;
2507 case ID_AR:
2508 return ICON_OUTLINER_DATA_ARMATURE;
2509 case ID_CA:
2510 return ICON_OUTLINER_DATA_CAMERA;
2511 case ID_KE:
2512 return ICON_SHAPEKEY_DATA;
2513 case ID_WO:
2514 return ICON_WORLD_DATA;
2515 case ID_AC:
2516 return ICON_ACTION;
2517 case ID_NLA:
2518 return ICON_NLA;
2519 case ID_TXT: {
2520 const Text *text = (Text *)id;
2521 if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
2522 return ICON_FILE_TEXT;
2523 }
2524 /* Helps distinguish text-based formats like the file-browser does. */
2525 return ED_file_extension_icon(text->filepath);
2526 }
2527 case ID_GR:
2528 return ICON_OUTLINER_COLLECTION;
2529 case ID_CV:
2530 return ICON_OUTLINER_DATA_CURVES;
2531 case ID_PT:
2532 return ICON_OUTLINER_DATA_POINTCLOUD;
2533 case ID_VO:
2534 return ICON_OUTLINER_DATA_VOLUME;
2535 case ID_LI:
2536 if (id->tag & ID_TAG_MISSING) {
2537 return ICON_LIBRARY_DATA_BROKEN;
2538 }
2539 else if (((Library *)id)->runtime.parent) {
2540 return ICON_LIBRARY_DATA_INDIRECT;
2541 }
2542 else {
2543 return ICON_LIBRARY_DATA_DIRECT;
2544 }
2545 case ID_LS:
2546 return ICON_LINE_DATA;
2547 case ID_GP:
2548 case ID_GD_LEGACY:
2549 return ICON_OUTLINER_DATA_GREASEPENCIL;
2550 case ID_LP: {
2551 const LightProbe *lp = (LightProbe *)id;
2552 switch (lp->type) {
2554 return ICON_LIGHTPROBE_SPHERE;
2556 return ICON_LIGHTPROBE_PLANE;
2558 return ICON_LIGHTPROBE_VOLUME;
2559 default:
2560 return ICON_LIGHTPROBE_SPHERE;
2561 }
2562 }
2563 case ID_BR:
2564 return ICON_BRUSH_DATA;
2565 case ID_SCR:
2566 case ID_WS:
2567 return ICON_WORKSPACE;
2568 case ID_MSK:
2569 return ICON_MOD_MASK;
2570 case ID_NT: {
2571 const bNodeTree *ntree = (bNodeTree *)id;
2572 const bke::bNodeTreeType *ntreetype = ntree->typeinfo;
2573 return ntreetype->ui_icon;
2574 }
2575 case ID_MC:
2576 return ICON_SEQUENCE;
2577 case ID_PC:
2578 return ICON_CURVE_BEZCURVE;
2579 case ID_PA:
2580 return ICON_PARTICLES;
2581 case ID_PAL:
2582 return ICON_COLOR;
2583 case ID_VF:
2584 return ICON_FILE_FONT;
2585 default:
2586 return ICON_NONE;
2587 }
2588}
2589
2591{
2592 TreeElementIcon data = {nullptr};
2593
2594 if (tselem->type != TSE_SOME_ID) {
2595 switch (tselem->type) {
2596 case TSE_ANIM_DATA:
2597 data.icon = ICON_ANIM_DATA; /* XXX */
2598 break;
2599 case TSE_NLA:
2600 data.icon = ICON_NLA;
2601 break;
2602 case TSE_NLA_TRACK:
2603 data.icon = ICON_NLA; /* XXX */
2604 break;
2605 case TSE_NLA_ACTION:
2606 data.icon = ICON_ACTION;
2607 break;
2608 case TSE_DRIVER_BASE:
2609 data.icon = ICON_DRIVER;
2610 break;
2611 case TSE_DEFGROUP_BASE:
2612 data.icon = ICON_GROUP_VERTEX;
2613 break;
2614 case TSE_DEFGROUP:
2615 data.icon = ICON_GROUP_VERTEX;
2616 break;
2617 case TSE_BONE:
2618 case TSE_EBONE:
2619 data.icon = ICON_BONE_DATA;
2620 break;
2622 data.icon = ICON_CONSTRAINT;
2623 data.drag_id = tselem->id;
2624 break;
2625 case TSE_CONSTRAINT: {
2626 bConstraint *con = static_cast<bConstraint *>(te->directdata);
2627 data.drag_id = tselem->id;
2628 switch ((eBConstraint_Types)con->type) {
2630 data.icon = ICON_CON_CAMERASOLVER;
2631 break;
2633 data.icon = ICON_CON_FOLLOWTRACK;
2634 break;
2636 data.icon = ICON_CON_OBJECTSOLVER;
2637 break;
2639 data.icon = ICON_CON_LOCLIKE;
2640 break;
2642 data.icon = ICON_CON_ROTLIKE;
2643 break;
2645 data.icon = ICON_CON_SIZELIKE;
2646 break;
2648 data.icon = ICON_CON_TRANSLIKE;
2649 break;
2651 data.icon = ICON_CON_DISTLIMIT;
2652 break;
2654 data.icon = ICON_CON_LOCLIMIT;
2655 break;
2657 data.icon = ICON_CON_ROTLIMIT;
2658 break;
2660 data.icon = ICON_CON_SIZELIMIT;
2661 break;
2663 data.icon = ICON_CON_SAMEVOL;
2664 break;
2666 data.icon = ICON_CON_TRANSFORM;
2667 break;
2669 data.icon = ICON_CON_TRANSFORM_CACHE;
2670 break;
2672 data.icon = ICON_CON_CLAMPTO;
2673 break;
2675 data.icon = ICON_CON_TRACKTO;
2676 break;
2678 data.icon = ICON_CON_KINEMATIC;
2679 break;
2681 data.icon = ICON_CON_LOCKTRACK;
2682 break;
2684 data.icon = ICON_CON_SPLINEIK;
2685 break;
2687 data.icon = ICON_CON_STRETCHTO;
2688 break;
2690 data.icon = ICON_CON_TRACKTO;
2691 break;
2693 data.icon = ICON_CON_ACTION;
2694 break;
2696 data.icon = ICON_CON_ARMATURE;
2697 break;
2699 data.icon = ICON_CON_CHILDOF;
2700 break;
2702 data.icon = ICON_CON_FLOOR;
2703 break;
2705 data.icon = ICON_CON_FOLLOWPATH;
2706 break;
2708 data.icon = ICON_CON_PIVOT;
2709 break;
2711 data.icon = ICON_CON_SHRINKWRAP;
2712 break;
2713
2714 default:
2715 data.icon = ICON_DOT;
2716 break;
2717 }
2718 break;
2719 }
2720 case TSE_MODIFIER_BASE:
2721 data.icon = ICON_MODIFIER_DATA;
2722 data.drag_id = tselem->id;
2723 break;
2726 data.icon = tree_element_get_icon_from_id(&base_te->id);
2727 break;
2728 }
2730 data.icon = ICON_LIBRARY_DATA_OVERRIDE;
2731 break;
2732 case TSE_LINKED_OB:
2733 data.icon = ICON_OBJECT_DATA;
2734 break;
2735 case TSE_LINKED_PSYS:
2736 data.icon = ICON_PARTICLES;
2737 break;
2738 case TSE_MODIFIER: {
2739 Object *ob = (Object *)tselem->id;
2740 data.drag_id = tselem->id;
2741
2742 if (ob->type != OB_GPENCIL_LEGACY) {
2743 ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr));
2744 const ModifierTypeInfo *modifier_type = static_cast<const ModifierTypeInfo *>(
2746 if (modifier_type != nullptr) {
2747 data.icon = modifier_type->icon;
2748 }
2749 else {
2750 data.icon = ICON_DOT;
2751 }
2752 }
2753 else {
2754 /* grease pencil modifiers */
2755 GpencilModifierData *md = static_cast<GpencilModifierData *>(
2756 BLI_findlink(&ob->greasepencil_modifiers, tselem->nr));
2757 switch ((GpencilModifierType)md->type) {
2759 data.icon = ICON_MOD_NOISE;
2760 break;
2762 data.icon = ICON_MOD_SUBSURF;
2763 break;
2765 data.icon = ICON_MOD_THICKNESS;
2766 break;
2768 data.icon = ICON_MOD_TINT;
2769 break;
2771 data.icon = ICON_MOD_ARRAY;
2772 break;
2774 data.icon = ICON_MOD_BUILD;
2775 break;
2777 data.icon = ICON_MOD_MASK;
2778 break;
2780 data.icon = ICON_MOD_HUE_SATURATION;
2781 break;
2783 data.icon = ICON_MOD_LATTICE;
2784 break;
2786 data.icon = ICON_MOD_MIRROR;
2787 break;
2789 data.icon = ICON_MOD_SIMPLIFY;
2790 break;
2792 data.icon = ICON_MOD_SMOOTH;
2793 break;
2795 data.icon = ICON_HOOK;
2796 break;
2798 data.icon = ICON_MOD_OFFSET;
2799 break;
2801 data.icon = ICON_MOD_ARMATURE;
2802 break;
2804 data.icon = ICON_GP_MULTIFRAME_EDITING;
2805 break;
2807 data.icon = ICON_MOD_TIME;
2808 break;
2810 data.icon = ICON_TEXTURE;
2811 break;
2813 data.icon = ICON_MOD_VERTEX_WEIGHT;
2814 break;
2816 data.icon = ICON_MOD_VERTEX_WEIGHT;
2817 break;
2819 data.icon = ICON_MOD_SHRINKWRAP;
2820 break;
2821
2822 /* Default */
2823 default:
2824 data.icon = ICON_DOT;
2825 break;
2826 }
2827 }
2828 break;
2829 }
2831 data.icon = ICON_NODETREE;
2832 break;
2833 case TSE_POSE_BASE:
2834 data.icon = ICON_ARMATURE_DATA;
2835 break;
2836 case TSE_POSE_CHANNEL:
2837 data.icon = ICON_BONE_DATA;
2838 break;
2839 case TSE_R_LAYER_BASE:
2840 data.icon = ICON_RENDERLAYERS;
2841 break;
2843 data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE;
2844 break;
2845 case TSE_R_LAYER:
2846 data.icon = ICON_RENDER_RESULT;
2847 break;
2850 data.icon = ICON_GROUP_BONE;
2851 break;
2852 case TSE_SEQUENCE: {
2854 switch (te_seq->get_sequence_type()) {
2855 case SEQ_TYPE_SCENE:
2856 data.icon = ICON_SCENE_DATA;
2857 break;
2858 case SEQ_TYPE_MOVIECLIP:
2859 data.icon = ICON_TRACKER;
2860 break;
2861 case SEQ_TYPE_MASK:
2862 data.icon = ICON_MOD_MASK;
2863 break;
2864 case SEQ_TYPE_MOVIE:
2865 data.icon = ICON_FILE_MOVIE;
2866 break;
2867 case SEQ_TYPE_SOUND_RAM:
2868 data.icon = ICON_SOUND;
2869 break;
2870 case SEQ_TYPE_IMAGE:
2871 data.icon = ICON_FILE_IMAGE;
2872 break;
2873 case SEQ_TYPE_COLOR:
2875 data.icon = ICON_COLOR;
2876 break;
2877 case SEQ_TYPE_TEXT:
2878 data.icon = ICON_FONT_DATA;
2879 break;
2880 case SEQ_TYPE_ADD:
2881 case SEQ_TYPE_SUB:
2882 case SEQ_TYPE_MUL:
2883 case SEQ_TYPE_OVERDROP:
2884 case SEQ_TYPE_ALPHAOVER:
2886 case SEQ_TYPE_COLORMIX:
2887 case SEQ_TYPE_MULTICAM:
2888 case SEQ_TYPE_TRANSFORM:
2889 case SEQ_TYPE_SPEED:
2890 case SEQ_TYPE_GLOW:
2892 data.icon = ICON_SHADERFX;
2893 break;
2894 case SEQ_TYPE_CROSS:
2895 case SEQ_TYPE_GAMCROSS:
2896 case SEQ_TYPE_WIPE:
2897 data.icon = ICON_ARROW_LEFTRIGHT;
2898 break;
2899 case SEQ_TYPE_META:
2900 data.icon = ICON_SEQ_STRIP_META;
2901 break;
2902 default:
2903 data.icon = ICON_DOT;
2904 break;
2905 }
2906 break;
2907 }
2908 case TSE_SEQ_STRIP:
2909 data.icon = ICON_LIBRARY_DATA_DIRECT;
2910 break;
2911 case TSE_SEQUENCE_DUP:
2912 data.icon = ICON_SEQ_STRIP_DUPLICATE;
2913 break;
2914 case TSE_RNA_STRUCT: {
2916 const PointerRNA &ptr = te_rna_struct->get_pointer_rna();
2917
2918 if (RNA_struct_is_ID(ptr.type)) {
2919 data.drag_id = static_cast<ID *>(ptr.data);
2920 data.icon = RNA_struct_ui_icon(ptr.type);
2921 }
2922 else {
2923 data.icon = RNA_struct_ui_icon(ptr.type);
2924 }
2925 break;
2926 }
2931 if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
2932 data.drag_id = tselem->id;
2933 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2934 }
2935
2936 data.icon = ICON_OUTLINER_COLLECTION;
2937 break;
2938 }
2939 case TSE_GP_LAYER: {
2940 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2941 break;
2942 }
2946 if (node.is_layer()) {
2947 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2948 }
2949 else if (node.is_group()) {
2950 const bke::greasepencil::LayerGroup &group = node.as_group();
2951
2952 data.icon = ICON_GREASEPENCIL_LAYER_GROUP;
2953 if (group.color_tag != LAYERGROUP_COLOR_NONE) {
2954 data.icon = ICON_LAYERGROUP_COLOR_01 + group.color_tag;
2955 }
2956 }
2957 break;
2958 }
2960 case TSE_GPENCIL_EFFECT:
2961 data.drag_id = tselem->id;
2962 data.icon = ICON_SHADERFX;
2963 break;
2964 default:
2965 data.icon = ICON_DOT;
2966 break;
2967 }
2968 }
2969 else if (tselem->id) {
2970 data.drag_id = tselem->id;
2971 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2972 data.icon = tree_element_get_icon_from_id(tselem->id);
2973 }
2974
2975 if (!te->abstract_element) {
2976 /* Pass */
2977 }
2978 else if (auto icon = te->abstract_element->get_icon()) {
2979 data.icon = *icon;
2980 }
2981
2982 return data;
2983}
2984
2988static bool tselem_draw_icon(uiBlock *block,
2989 int xmax,
2990 float x,
2991 float y,
2992 TreeStoreElem *tselem,
2993 TreeElement *te,
2994 float alpha,
2995 const bool is_clickable,
2996 const int num_elements)
2997{
2998 TreeElementIcon data = tree_element_get_icon(tselem, te);
2999 if (data.icon == 0) {
3000 return false;
3001 }
3002
3003 const bool is_collection = outliner_is_collection_tree_element(te);
3004 IconTextOverlay text_overlay;
3005 UI_icon_text_overlay_init_from_count(&text_overlay, num_elements);
3006
3007 /* Collection colors and icons covered by restrict buttons. */
3008 if (!is_clickable || x >= xmax || is_collection) {
3009 /* Placement of icons, copied from `interface_widgets.cc`. */
3010 float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
3011 x += 2.0f * aspect;
3012 y += 2.0f * aspect;
3013 bTheme *btheme = UI_GetTheme();
3014
3015 if (is_collection) {
3017 if (collection->color_tag != COLLECTION_COLOR_NONE) {
3019 y,
3020 data.icon,
3022 alpha,
3023 0.0f,
3024 btheme->collection_color[collection->color_tag].color,
3025 btheme->tui.icon_border_intensity > 0.0f,
3026 &text_overlay);
3027 return true;
3028 }
3029 }
3030
3031 /* Reduce alpha to match icon buttons */
3032 alpha *= 0.8f;
3033
3034 /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */
3035 uchar color[4];
3036 if (UI_icon_get_theme_color(data.icon, color)) {
3038 y,
3039 data.icon,
3041 alpha,
3042 0.0f,
3043 color,
3044 btheme->tui.icon_border_intensity > 0.0f,
3045 &text_overlay);
3046 }
3047 else {
3049 x, y, data.icon, UI_INV_SCALE_FAC, alpha, 0.0f, nullptr, false, &text_overlay);
3050 }
3051 }
3052 else {
3053 uiBut *but = uiDefIconBut(
3054 block,
3056 0,
3057 data.icon,
3058 x,
3059 y,
3060 UI_UNIT_X,
3061 UI_UNIT_Y,
3062 nullptr,
3063 0.0,
3064 0.0,
3065 (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->filepath : "");
3067 }
3068
3069 return true;
3070}
3071
3072static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
3073{
3074 float text[4];
3076
3077 copy_v3_v3(icon_color, text);
3078 icon_color[3] = 0.4f;
3079 copy_v3_v3(icon_border, text);
3080 icon_border[3] = 0.2f;
3081}
3082
3083/* Draw a rounded rectangle behind icons of active elements. */
3084static void outliner_draw_active_indicator(const float minx,
3085 const float miny,
3086 const float maxx,
3087 const float maxy,
3088 const float icon_color[4],
3089 const float icon_border[4])
3090{
3091 const float ufac = UI_UNIT_X / 20.0f;
3092 const float radius = UI_UNIT_Y / 4.0f;
3093 rctf rect{};
3094 BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
3095
3097 UI_draw_roundbox_aa(&rect, true, radius, icon_color);
3098 UI_draw_roundbox_aa(&rect, false, radius, icon_border);
3099 GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */
3100}
3101
3103 TreeElement *te,
3104 int xmax,
3105 int *offsx,
3106 int ys,
3107 float alpha_fac,
3108 const eOLDrawState active,
3109 const int num_elements)
3110{
3111 TreeStoreElem *tselem = TREESTORE(te);
3112
3113 if (active != OL_DRAWSEL_NONE) {
3114 float icon_color[4], icon_border[4];
3115 outliner_icon_background_colors(icon_color, icon_border);
3116 if (active == OL_DRAWSEL_ACTIVE) {
3118 icon_border[3] = 0.3f;
3119 }
3120
3121 outliner_draw_active_indicator(float(*offsx),
3122 float(ys),
3123 float(*offsx) + UI_UNIT_X,
3124 float(ys) + UI_UNIT_Y,
3125 icon_color,
3126 icon_border);
3127 }
3128
3129 if (tselem->flag & TSE_HIGHLIGHTED_ICON) {
3130 alpha_fac += 0.5;
3131 }
3133 block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements);
3134 te->xs = *offsx;
3135 te->ys = ys;
3136 te->xend = short(*offsx) + UI_UNIT_X;
3137
3138 if (num_elements > 1) {
3139 te->flag |= TE_ICONROW_MERGED;
3140 }
3141 else {
3142 te->flag |= TE_ICONROW;
3143 }
3144
3145 (*offsx) += UI_UNIT_X;
3146}
3147
3149{
3150 TreeStoreElem *tselem = TREESTORE(te);
3151
3152 int id_index = 0;
3153 if (tselem->type == TSE_SOME_ID) {
3154 id_index = BKE_idtype_idcode_to_index(te->idcode);
3155 }
3156 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3157 /* Use the index of the grease pencil ID for the grease pencil tree nodes (which are not IDs).
3158 * All the Grease Pencil layer tree stats are stored in this index in #MergedIconRow. */
3159 id_index = INDEX_ID_GP;
3160 }
3161 else {
3162 id_index = INDEX_ID_GR;
3163 }
3164
3165 if (id_index < INDEX_ID_OB) {
3166 return id_index;
3167 }
3168 if (id_index == INDEX_ID_OB) {
3169 const Object *ob = (Object *)tselem->id;
3170 return INDEX_ID_OB + ob->type;
3171 }
3172 return id_index + OB_TYPE_MAX;
3173}
3174
3180
3182 uiBlock *block,
3183 const uiFontStyle *fstyle,
3184 const TreeViewContext *tvc,
3185 SpaceOutliner *space_outliner,
3186 ListBase *lb,
3187 int level,
3188 int xmax,
3189 int *offsx,
3190 int ys,
3191 float alpha_fac,
3192 bool in_bone_hierarchy,
3193 const bool is_grease_pencil_node_hierarchy,
3194 MergedIconRow *merged)
3195{
3197
3198 LISTBASE_FOREACH (TreeElement *, te, lb) {
3199 TreeStoreElem *tselem = TREESTORE(te);
3200 te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
3201
3202 /* object hierarchy always, further constrained on level */
3203 /* Bones are also hierarchies and get a merged count, but we only start recursing into them if
3204 * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed
3205 * collection). */
3206 const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL);
3207 /* The Grease Pencil layer tree is a hierarchy where we merge and count the total number of
3208 * layers in a node. We merge the counts for all the layers and skip counting nodes that are
3209 * layer groups (for less visual clutter in the outliner). */
3210 const bool is_grease_pencil_node = (tselem->type == TSE_GREASE_PENCIL_NODE);
3211 if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
3212 (is_grease_pencil_node_hierarchy && is_grease_pencil_node) ||
3213 (in_bone_hierarchy && is_bone))
3214 {
3215 /* active blocks get white circle */
3216 if (tselem->type == TSE_SOME_ID) {
3217 if (te->idcode == ID_OB) {
3218 active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
3219 }
3220 else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
3221 active = OL_DRAWSEL_ACTIVE;
3222 }
3223 else {
3224 active = tree_element_active_state_get(tvc, te, tselem);
3225 }
3226 }
3227 else {
3228 active = tree_element_type_active_state_get(C, tvc, te, tselem);
3229 }
3230
3231 if (!ELEM(tselem->type,
3241 TSE_BONE,
3242 TSE_EBONE,
3245 TSE_DEFGROUP))
3246 {
3247 outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1);
3248 }
3249 else if (tselem->type == TSE_GREASE_PENCIL_NODE &&
3251 {
3252 /* Grease Pencil layer groups are tree nodes, but they shouldn't be counted. We only want
3253 * to keep track of the nodes that are layers and show the total number of layers in a
3254 * node. Adding the count of groups would add a lot of clutter. */
3255 }
3256 else {
3257 const int index = tree_element_id_type_to_index(te);
3258 merged->num_elements[index]++;
3259 if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
3260 merged->tree_element[index] = te;
3261 }
3262 merged->active[index] = std::max(active, merged->active[index]);
3263 }
3264 }
3265
3266 /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */
3267 /* Also only recurse into bone hierarchies if a direct child of the collapsed element to
3268 * merge into. */
3269 const bool is_root_level_bone = is_bone && (level == 0);
3270 in_bone_hierarchy |= is_root_level_bone;
3271 /* Recurse into the grease pencil layer tree if we already are in the hierarchy or if we're at
3272 * the root level and find a grease pencil node. */
3273 const bool in_grease_pencil_node_hierarchy = is_grease_pencil_node_hierarchy ||
3274 (is_grease_pencil_node && level == 0);
3276 in_bone_hierarchy || in_grease_pencil_node_hierarchy)
3277 {
3279 block,
3280 fstyle,
3281 tvc,
3282 space_outliner,
3283 &te->subtree,
3284 level + 1,
3285 xmax,
3286 offsx,
3287 ys,
3288 alpha_fac,
3289 in_bone_hierarchy,
3290 in_grease_pencil_node_hierarchy,
3291 merged);
3292 }
3293 }
3294
3295 if (level == 0) {
3296 for (int i = 0; i < INDEX_ID_MAX; i++) {
3297 const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1;
3298 /* See tree_element_id_type_to_index for the index logic. */
3299 int index_base = i;
3300 if (i > INDEX_ID_OB) {
3301 index_base += OB_TYPE_MAX;
3302 }
3303 for (int j = 0; j < num_subtypes; j++) {
3304 const int index = index_base + j;
3305 if (merged->num_elements[index] != 0) {
3307 merged->tree_element[index],
3308 xmax,
3309 offsx,
3310 ys,
3311 alpha_fac,
3312 merged->active[index],
3313 merged->num_elements[index]);
3314 }
3315 }
3316 }
3317 }
3318}
3319
3320/* closed tree element */
3322{
3323 tree_iterator::all(te->subtree, [&](TreeElement *te) {
3324 /* closed items may be displayed in row of parent, don't change their coordinate! */
3325 if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
3326 te->xs = 0;
3327 te->ys = 0;
3328 te->xend = 0;
3329 }
3330 });
3331}
3332
3334 const TreeElement *te,
3335 const TreeStoreElem *tselem)
3336{
3337 if (tselem->type == TSE_SOME_ID) {
3338 switch (te->idcode) {
3339 case ID_OB: {
3340 const Object *ob = (const Object *)tselem->id;
3341 /* Lookup in view layer is logically const as it only checks a cache. */
3343 const Base *base = (te->directdata) ? (const Base *)te->directdata :
3345 (ViewLayer *)tvc->view_layer, (Object *)ob);
3346 const bool is_visible = (base != nullptr) &&
3348
3349 return !is_visible;
3350 }
3351 default: {
3352 if (te->parent) {
3353 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3354 }
3355 }
3356 }
3357 }
3358 switch (tselem->type) {
3359 case TSE_LAYER_COLLECTION: {
3360 const LayerCollection *layer_collection = (const LayerCollection *)te->directdata;
3361 const bool is_visible = layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER;
3362 const bool is_excluded = layer_collection->flag & LAYER_COLLECTION_EXCLUDE;
3363 return !is_visible || is_excluded;
3364 }
3367 tree_element_cast<TreeElementGreasePencilNode>(te)->node();
3368 return !node.is_visible();
3369 }
3370 default: {
3371 if (te->parent) {
3372 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3373 }
3374 }
3375 }
3376
3377 if (te->flag & TE_CHILD_NOT_IN_COLLECTION) {
3378 return true;
3379 }
3380
3381 return false;
3382}
3383
3385 uiBlock *block,
3386 const uiFontStyle *fstyle,
3387 const TreeViewContext *tvc,
3388 ARegion *region,
3389 SpaceOutliner *space_outliner,
3390 TreeElement *te,
3391 bool draw_grayed_out,
3392 int startx,
3393 int *starty,
3394 const float restrict_column_width,
3395 TreeElement **te_edit)
3396{
3397 TreeStoreElem *tselem = TREESTORE(te);
3398 float ufac = UI_UNIT_X / 20.0f;
3399 int offsx = 0;
3401 uchar text_color[4];
3402 UI_GetThemeColor4ubv(TH_TEXT, text_color);
3403 float icon_bgcolor[4], icon_border[4];
3404 outliner_icon_background_colors(icon_bgcolor, icon_border);
3405
3406 if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) {
3407 const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
3408 int xmax = region->v2d.cur.xmax;
3409
3410 if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
3411 *te_edit = te;
3412 }
3413
3414 /* Icons can be UI buts, we don't want it to overlap with restrict. */
3415 if (restrict_column_width > 0) {
3416 xmax -= restrict_column_width + UI_UNIT_X;
3417 }
3418
3420
3421 /* Colors for active/selected data. */
3422 if (tselem->type == TSE_SOME_ID) {
3423 if (te->idcode == ID_OB) {
3424 Object *ob = (Object *)tselem->id;
3426 Base *base = (te->directdata) ? (Base *)te->directdata :
3428 const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
3429
3430 if (ob == tvc->obact) {
3431 active = OL_DRAWSEL_ACTIVE;
3432 }
3433
3434 if (is_selected) {
3435 if (ob == tvc->obact) {
3436 /* Active selected object. */
3438 text_color[3] = 255;
3439 }
3440 else {
3441 /* Other selected objects. */
3443 text_color[3] = 255;
3444 }
3445 }
3446 }
3447 else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
3448 /* Objects being edited. */
3450 icon_border[3] = 0.3f;
3451 active = OL_DRAWSEL_ACTIVE;
3452 }
3453 else {
3454 if (tree_element_active_state_get(tvc, te, tselem)) {
3455 /* Active items like camera or material. */
3456 icon_bgcolor[3] = 0.2f;
3457 active = OL_DRAWSEL_ACTIVE;
3458 }
3459 }
3460 }
3461 else {
3462 active = tree_element_type_active_state_get(C, tvc, te, tselem);
3463 }
3464
3465 /* Active circle. */
3466 if (active != OL_DRAWSEL_NONE) {
3467 outliner_draw_active_indicator(float(startx) + offsx + UI_UNIT_X,
3468 float(*starty),
3469 float(startx) + offsx + 2.0f * UI_UNIT_X,
3470 float(*starty) + UI_UNIT_Y,
3471 icon_bgcolor,
3472 icon_border);
3473
3474 te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */
3475 }
3476
3477 if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
3478 /* Scene collection in view layer can't expand/collapse. */
3479 }
3480 else if (te->subtree.first || (te->flag & TE_PRETEND_HAS_CHILDREN)) {
3481 /* Open/close icon, only when sub-levels, except for scene. */
3482 int icon_x = startx;
3483
3484 /* Icons a bit higher. */
3485 if (TSELEM_OPEN(tselem, space_outliner)) {
3487 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_DOWNARROW_HLT, alpha_fac);
3488 }
3489 else {
3491 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_RIGHTARROW, alpha_fac);
3492 }
3493 }
3494 offsx += UI_UNIT_X;
3495
3496 /* Data-type icon. */
3498 tselem_draw_icon(block,
3499 xmax,
3500 float(startx) + offsx,
3501 float(*starty),
3502 tselem,
3503 te,
3504 (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
3505 true,
3506 1))
3507 {
3508 offsx += UI_UNIT_X + 4 * ufac;
3509 }
3510 else {
3511 offsx += 2 * ufac;
3512 }
3513
3514 const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
3516 (te_rna_struct && RNA_struct_is_ID(te_rna_struct->get_pointer_rna().type)))
3517 {
3518 const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
3519 if (lib_icon != ICON_NONE) {
3521 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, lib_icon, alpha_fac);
3522 offsx += UI_UNIT_X + 4 * ufac;
3523 }
3524
3525 if (tselem->type == TSE_LAYER_COLLECTION) {
3526 const Collection *collection = (Collection *)tselem->id;
3527 if (!BLI_listbase_is_empty(&collection->exporters)) {
3529 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, ICON_EXPORT, alpha_fac);
3530 offsx += UI_UNIT_X + 4 * ufac;
3531 }
3532 }
3533 }
3535
3536 /* Name. */
3537 if ((tselem->flag & TSE_TEXTBUT) == 0) {
3539 UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_color);
3540 text_color[3] = 255;
3541 }
3542 text_color[3] *= alpha_fac;
3543 UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_color);
3544 }
3545
3546 offsx += int(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
3547
3548 /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */
3549 if (!TSELEM_OPEN(tselem, space_outliner)) {
3550 if (te->subtree.first) {
3551 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
3552 /* Pass. */
3553 }
3554 /* this tree element always has same amount of branches, so don't draw */
3555 else if (tselem->type != TSE_R_LAYER) {
3556 int tempx = startx + offsx;
3557
3559
3560 MergedIconRow merged{};
3562 block,
3563 fstyle,
3564 tvc,
3565 space_outliner,
3566 &te->subtree,
3567 0,
3568 xmax,
3569 &tempx,
3570 *starty,
3571 alpha_fac,
3572 false,
3573 false,
3574 &merged);
3575
3577 }
3578 }
3579 }
3580 }
3581 /* Store coord and continue, we need coordinates for elements outside view too. */
3582 te->xs = startx;
3583 te->ys = *starty;
3584 te->xend = startx + offsx;
3585
3586 if (TSELEM_OPEN(tselem, space_outliner)) {
3587 *starty -= UI_UNIT_Y;
3588
3589 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
3590 /* Check if element needs to be drawn grayed out, but also gray out
3591 * children of a grayed out parent (pass on draw_grayed_out to children). */
3592 bool draw_children_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
3594 block,
3595 fstyle,
3596 tvc,
3597 region,
3598 space_outliner,
3599 ten,
3600 draw_children_grayed_out,
3601 startx + UI_UNIT_X,
3602 starty,
3603 restrict_column_width,
3604 te_edit);
3605 }
3606 }
3607 else {
3609 *starty -= UI_UNIT_Y;
3610 }
3611}
3612
3614{
3615 LISTBASE_FOREACH (TreeElement *, te, lb) {
3616 TreeStoreElem *tselem = TREESTORE(te);
3617 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3618 return true;
3619 }
3620 }
3621 return false;
3622}
3623
3625 const uint pos, const int x, const int y1, const int y2, const bool draw_dashed)
3626{
3627 /* Small vertical padding. */
3628 const short line_padding = UI_UNIT_Y / 4.0f;
3629
3630 /* >= is 1.0 for un-dashed lines. */
3631 immUniform1f("udash_factor", draw_dashed ? 0.5f : 1.0f);
3632
3634 /* Intentionally draw from top to bottom, so collapsing a child item doesn't make the dashes
3635 * appear to move. */
3636 immVertex2f(pos, x, y2 + line_padding);
3637 immVertex2f(pos, x, y1 - line_padding);
3638 immEnd();
3639}
3640
3642 SpaceOutliner *space_outliner,
3643 ListBase *lb,
3644 const TreeViewContext *tvc,
3645 int startx,
3646 const uchar col[4],
3647 bool draw_grayed_out,
3648 int *starty)
3649{
3650 bTheme *btheme = UI_GetTheme();
3651 int y = *starty;
3652
3653 /* Draw vertical lines between collections */
3654 bool draw_hierarchy_line;
3655 bool is_object_line;
3656 LISTBASE_FOREACH (TreeElement *, te, lb) {
3657 TreeStoreElem *tselem = TREESTORE(te);
3658 draw_hierarchy_line = false;
3659 is_object_line = false;
3660 *starty -= UI_UNIT_Y;
3661 short color_tag = COLLECTION_COLOR_NONE;
3662
3663 /* Only draw hierarchy lines for expanded collections and objects with children. */
3664 if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
3665 if (tselem->type == TSE_LAYER_COLLECTION) {
3666 draw_hierarchy_line = true;
3667
3669 color_tag = collection->color_tag;
3670
3671 y = *starty;
3672 }
3673 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3674 if (subtree_contains_object(&te->subtree)) {
3675 draw_hierarchy_line = true;
3676 is_object_line = true;
3677 y = *starty;
3678 }
3679 }
3680 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3682 tree_element_cast<TreeElementGreasePencilNode>(te)->node();
3683 if (node.is_group() && node.as_group().num_direct_nodes() > 0) {
3684 draw_hierarchy_line = true;
3685 y = *starty;
3686 }
3687 }
3688
3690 space_outliner,
3691 &te->subtree,
3692 tvc,
3693 startx + UI_UNIT_X,
3694 col,
3695 draw_grayed_out,
3696 starty);
3697 }
3698
3699 if (draw_hierarchy_line) {
3700 const short alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 127 : 255;
3701 uchar line_color[4];
3702 if (color_tag != COLLECTION_COLOR_NONE) {
3703 copy_v4_v4_uchar(line_color, btheme->collection_color[color_tag].color);
3704 }
3705 else {
3706 copy_v4_v4_uchar(line_color, col);
3707 }
3708
3709 line_color[3] = alpha_fac;
3710 immUniformColor4ubv(line_color);
3711 outliner_draw_hierarchy_line(pos, startx, y, *starty, is_object_line);
3712 }
3713 }
3714}
3715
3717 ListBase *lb,
3718 const TreeViewContext *tvc,
3719 int startx,
3720 int *starty)
3721{
3724 uchar col[4];
3725
3727
3728 float viewport_size[4];
3729 GPU_viewport_size_get_f(viewport_size);
3730 immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
3731 immUniform1i("colors_len", 0); /* "simple" mode */
3732 immUniform1f("dash_width", 8.0f);
3734 col[3] = 255;
3735
3736 GPU_line_width(1.0f);
3739 pos, space_outliner, lb, tvc, startx, col, false, starty);
3741
3743}
3744
3746 SpaceOutliner *space_outliner,
3747 ListBase *lb,
3748 int *starty)
3749{
3750 LISTBASE_FOREACH (TreeElement *, te, lb) {
3751 TreeStoreElem *tselem = TREESTORE(te);
3752
3753 /* Selection status. */
3754 if (TSELEM_OPEN(tselem, space_outliner)) {
3755 if (tselem->type == TSE_RNA_STRUCT) {
3759 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3760 immRecti(pos, 0, *starty + 1, int(region->v2d.cur.xmax), *starty + UI_UNIT_Y - 1);
3762 }
3763 }
3764
3765 *starty -= UI_UNIT_Y;
3766 if (TSELEM_OPEN(tselem, space_outliner)) {
3767 outliner_draw_struct_marks(region, space_outliner, &te->subtree, starty);
3768 if (tselem->type == TSE_RNA_STRUCT) {
3772 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3773
3775 immVertex2f(pos, 0, float(*starty) + UI_UNIT_Y);
3776 immVertex2f(pos, region->v2d.cur.xmax, float(*starty) + UI_UNIT_Y);
3777 immEnd();
3778
3780 }
3781 }
3782 }
3783}
3784
3786 const ARegion *region,
3787 const SpaceOutliner *space_outliner,
3788 const float col_selection[4],
3789 const float col_active[4],
3790 const float col_highlight[4],
3791 const float col_searchmatch[4],
3792 int start_x,
3793 int *io_start_y)
3794{
3795 const bool is_searching = (SEARCHING_OUTLINER(space_outliner) ||
3796 (space_outliner->outlinevis == SO_DATA_API &&
3797 space_outliner->search_string[0] != 0));
3798
3799 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
3800 const TreeStoreElem *tselem = TREESTORE(te);
3801 const int start_y = *io_start_y;
3802
3803 /* Selection status. */
3804 if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
3805 immUniformColor4fv(col_active);
3806 immRecti(pos, 0, start_y, int(region->v2d.cur.xmax), start_y + UI_UNIT_Y);
3807 }
3808 else if (tselem->flag & TSE_SELECTED) {
3809 immUniformColor4fv(col_selection);
3810 immRecti(pos, 0, start_y, int(region->v2d.cur.xmax), start_y + UI_UNIT_Y);
3811 }
3812
3813 /* Highlights. */
3814 if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
3815 const int end_x = int(region->v2d.cur.xmax);
3816
3817 if (tselem->flag & TSE_DRAG_ANY) {
3818 /* Drag and drop highlight. */
3819 float col[4];
3821
3822 if (tselem->flag & TSE_DRAG_BEFORE) {
3824 immRecti(pos,
3825 start_x,
3826 start_y + UI_UNIT_Y - U.pixelsize,
3827 end_x,
3828 start_y + UI_UNIT_Y + U.pixelsize);
3829 }
3830 else if (tselem->flag & TSE_DRAG_AFTER) {
3832 immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize);
3833 }
3834 else {
3835 immUniformColor3fvAlpha(col, col[3] * 0.5f);
3836 immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
3837 }
3838 }
3839 else {
3840 if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
3841 /* Search match highlights. We don't expand items when searching in the data-blocks,
3842 * but we still want to highlight any filter matches. */
3843 immUniformColor4fv(col_searchmatch);
3844 immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
3845 }
3846 else if (tselem->flag & TSE_HIGHLIGHTED) {
3847 /* Mouse hover highlight. */
3848 immUniformColor4fv(col_highlight);
3849 immRecti(pos, 0, start_y, end_x, start_y + UI_UNIT_Y);
3850 }
3851 }
3852 }
3853
3854 *io_start_y -= UI_UNIT_Y;
3855 });
3856}
3857
3859 SpaceOutliner *space_outliner,
3860 int startx,
3861 int *starty)
3862{
3863 const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
3864 float col_selection[4], col_active[4], col_searchmatch[4];
3865
3867 col_selection[3] = 1.0f; /* No alpha. */
3869 col_active[3] = 1.0f; /* No alpha. */
3870 UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
3871 col_searchmatch[3] = 0.5f;
3872
3878 region,
3879 space_outliner,
3880 col_selection,
3881 col_active,
3882 col_highlight,
3883 col_searchmatch,
3884 startx,
3885 starty);
3888}
3889
3891 uiBlock *block,
3892 const TreeViewContext *tvc,
3893 ARegion *region,
3894 SpaceOutliner *space_outliner,
3895 const float right_column_width,
3896 const bool use_mode_column,
3897 const bool use_warning_column,
3898 TreeElement **te_edit)
3899{
3900 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
3901 int starty, startx;
3902
3903 /* Move the tree a unit left in view layer mode */
3904 short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
3905 UI_UNIT_X :
3906 0;
3907 if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
3908 columns_offset -= UI_UNIT_X;
3909 }
3910
3911 if (use_warning_column) {
3912 columns_offset += UI_UNIT_X;
3913 }
3914
3915 GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
3916
3917 if (space_outliner->outlinevis == SO_DATA_API) {
3918 /* struct marks */
3919 starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3920 outliner_draw_struct_marks(region, space_outliner, &space_outliner->tree, &starty);
3921 }
3922
3923 /* Draw highlights before hierarchy. */
3924 starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3925 startx = 0;
3926 outliner_draw_highlights(region, space_outliner, startx, &starty);
3927
3928 /* Set scissor so tree elements or lines can't overlap restriction icons. */
3929 int scissor[4] = {0};
3930 if (right_column_width > 0.0f) {
3931 int mask_x = BLI_rcti_size_x(&region->v2d.mask) - int(right_column_width) + 1;
3932 CLAMP_MIN(mask_x, 0);
3933
3934 GPU_scissor_get(scissor);
3935 GPU_scissor(0, 0, mask_x, region->winy);
3936 }
3937
3938 /* Draw hierarchy lines for collections and object children. */
3939 starty = int(region->v2d.tot.ymax) - OL_Y_OFFSET;
3940 startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
3941 outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, tvc, startx, &starty);
3942
3943 /* Items themselves. */
3944 starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3945 startx = columns_offset;
3946 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
3948 block,
3949 fstyle,
3950 tvc,
3951 region,
3952 space_outliner,
3953 te,
3954 (te->flag & TE_DRAGGING) != 0,
3955 startx,
3956 &starty,
3957 right_column_width,
3958 te_edit);
3959 }
3960
3961 if (right_column_width > 0.0f) {
3962 /* Reset scissor. */
3963 GPU_scissor(UNPACK4(scissor));
3964 }
3965}
3966
3967static void outliner_back(ARegion *region)
3968{
3969 int ystart;
3970
3971 ystart = int(region->v2d.tot.ymax);
3972 ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
3973
3976
3978
3979 float col_alternating[4];
3980 UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating);
3982
3983 const float x1 = 0.0f, x2 = region->v2d.cur.xmax;
3984 float y1 = ystart, y2;
3985 int tot = int(floor(ystart - region->v2d.cur.ymin + 2 * UI_UNIT_Y)) / (2 * UI_UNIT_Y);
3986
3987 if (tot > 0) {
3988 immBegin(GPU_PRIM_TRIS, 6 * tot);
3989 while (tot--) {
3990 y1 -= 2 * UI_UNIT_Y;
3991 y2 = y1 + UI_UNIT_Y;
3992 immVertex2f(pos, x1, y1);
3993 immVertex2f(pos, x2, y1);
3994 immVertex2f(pos, x2, y2);
3995
3996 immVertex2f(pos, x1, y1);
3997 immVertex2f(pos, x2, y2);
3998 immVertex2f(pos, x1, y2);
3999 }
4000 immEnd();
4001 }
4003}
4004
4005static int outliner_data_api_buttons_start_x(int max_tree_width)
4006{
4007 return max_ii(OL_RNA_COLX, max_tree_width + OL_RNA_COL_SPACEX);
4008}
4009
4010static int outliner_width(SpaceOutliner *space_outliner,
4011 int max_tree_width,
4012 float right_column_width)
4013{
4014 if (space_outliner->outlinevis == SO_DATA_API) {
4015 return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX +
4016 10 * UI_SCALE_FAC;
4017 }
4018 return max_tree_width + right_column_width;
4019}
4020
4022 SpaceOutliner *space_outliner,
4023 int tree_width,
4024 int tree_height,
4025 float right_column_width)
4026{
4027 int sizex = outliner_width(space_outliner, tree_width, right_column_width);
4028 int sizey = tree_height;
4029
4030 /* Extend size to allow for horizontal scroll-bar and extra offset. */
4031 sizey += V2D_SCROLL_HEIGHT + OL_Y_OFFSET;
4032
4033 UI_view2d_totRect_set(&region->v2d, sizex, sizey);
4034}
4035
4038/* -------------------------------------------------------------------- */
4044void draw_outliner(const bContext *C, bool do_rebuild)
4045{
4046 Main *mainvar = CTX_data_main(C);
4047 ARegion *region = CTX_wm_region(C);
4048 View2D *v2d = &region->v2d;
4049 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
4050 uiBlock *block;
4051 TreeElement *te_edit = nullptr;
4052
4053 TreeViewContext tvc;
4055
4056 /* FIXME(@ideasman42): There is an order of initialization problem here between
4057 * `v2d->cur` & `v2d->tot` where this function reads from `v2d->cur` for the scroll position
4058 * but may reset the scroll position *without* drawing into the clamped position.
4059 *
4060 * The `on_scroll` argument is used for an optional second draw pass.
4061 *
4062 * See `USE_OUTLINER_DRAW_CLAMPS_SCROLL_HACK` & #128346 for a full description. */
4063
4064 if (do_rebuild) {
4065 outliner_build_tree(mainvar, tvc.scene, tvc.view_layer, space_outliner, region); /* Always. */
4066
4067 /* If global sync select is dirty, flag other outliners. */
4070 }
4071
4072 /* Sync selection state from view layer. */
4073 if (!ELEM(space_outliner->outlinevis,
4077 SO_ID_ORPHANS) &&
4078 space_outliner->flag & SO_SYNC_SELECT)
4079 {
4080 outliner_sync_selection(C, space_outliner);
4081 }
4082 }
4083
4084 /* Force display to pixel coords. */
4086 /* Set matrix for 2D-view controls. */
4088
4089 /* Only show mode column in View Layers and Scenes view. */
4090 const bool use_mode_column = outliner_shows_mode_column(*space_outliner);
4091 const bool use_warning_column = outliner_has_element_warnings(*space_outliner);
4092
4093 /* Draw outliner stuff (background, hierarchy lines and names). */
4094 const float right_column_width = outliner_right_columns_width(space_outliner);
4095 outliner_back(region);
4096 block = UI_block_begin(C, region, __func__, UI_EMBOSS);
4098 block,
4099 &tvc,
4100 region,
4101 space_outliner,
4102 right_column_width,
4103 use_mode_column,
4104 use_warning_column,
4105 &te_edit);
4106
4107 /* Compute outliner dimensions after it has been drawn. */
4108 int tree_width, tree_height;
4109 outliner_tree_dimensions(space_outliner, &tree_width, &tree_height);
4110
4111 /* Default to no emboss for outliner UI. */
4113
4114 if (space_outliner->outlinevis == SO_DATA_API) {
4115 int buttons_start_x = outliner_data_api_buttons_start_x(tree_width);
4116 /* draw rna buttons */
4117 outliner_draw_separator(region, buttons_start_x);
4118 outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
4119
4121 outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x);
4123 }
4124 else if (ELEM(space_outliner->outlinevis, SO_ID_ORPHANS, SO_LIBRARIES)) {
4125 outliner_draw_userbuts(block, region, space_outliner);
4126 }
4127 else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
4128 const int x = region->v2d.cur.xmax - right_column_width;
4129 outliner_draw_separator(region, x);
4133 outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x);
4135 }
4136 else if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_HIERARCHIES) {
4138 mainvar, block, region, space_outliner, &space_outliner->tree, x);
4139 }
4140 }
4141 else if (right_column_width > 0.0f) {
4142 /* draw restriction columns */
4143 RestrictPropertiesActive props_active;
4144 memset(&props_active, 1, sizeof(RestrictPropertiesActive));
4146 tvc.scene,
4147 tvc.view_layer,
4148 region,
4149 space_outliner,
4150 &space_outliner->tree,
4151 props_active);
4152 }
4153
4154 /* Draw mode icons */
4155 if (use_mode_column) {
4156 outliner_draw_mode_column(block, &tvc, space_outliner);
4157 }
4158
4159 /* Draw warning icons */
4160 if (use_warning_column) {
4161 outliner_draw_warning_column(block, space_outliner, use_mode_column);
4162 }
4163
4165
4166 /* Draw edit buttons if necessary. */
4167 if (te_edit) {
4168 outliner_buttons(C, block, region, right_column_width, te_edit);
4169 }
4170
4171 UI_block_end(C, block);
4172 UI_block_draw(C, block);
4173
4174 /* Update total viewable region. */
4176 region, space_outliner, tree_width, tree_height, right_column_width);
4177}
4178
4181} // namespace blender::ed::outliner
4182
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_name_set(bArmature *armature, BoneCollection *bcoll, const char *name)
bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
ReportList * CTX_wm_reports(const bContext *C)
SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(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)
short BKE_curve_type_get(const Curve *cu)
Definition curve.cc:416
support for deformation groups and hooks.
void BKE_object_defgroup_unique_name(bDeformGroup *dg, Object *ob)
Definition deform.cc:752
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Low-level operations for grease pencil.
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:232
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
void BKE_main_collection_sync_remap(const Main *bmain)
void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent, LayerCollection *lc_child)
void BKE_view_layer_need_resync_tag(ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
Definition library.cc:135
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
bool BKE_object_data_is_in_editmode(const Object *ob, const ID *id)
bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_child)
struct ParticleSystem * psys_get_current(struct Object *ob)
Definition particle.cc:534
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE int max_ii(int a, int b)
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.c:408
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
#define STRNCPY(dst, src)
Definition BLI_string.h:593
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE], int number_to_format) ATTR_NONNULL(1)
Definition string.c:1279
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
#define UNPACK4(a)
#define ELEM(...)
#define CLAMP_MIN(a, b)
#define TIP_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
#define ID_FAKE_USERS(id)
Definition DNA_ID.h:616
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1071
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define MAX_ID_NAME
Definition DNA_ID.h:377
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:720
@ ID_TAG_EXTRAUSER
Definition DNA_ID.h:824
@ ID_TAG_MISSING
Definition DNA_ID.h:813
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:367
@ INDEX_ID_GR
Definition DNA_ID.h:1308
@ INDEX_ID_OB
Definition DNA_ID.h:1307
@ INDEX_ID_GP
Definition DNA_ID.h:1304
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_CA
@ ID_AR
@ ID_MC
@ ID_LI
@ ID_TE
@ ID_IM
@ ID_VO
@ ID_WS
@ ID_NT
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SO
@ ID_SCE
@ ID_LS
@ ID_MSK
@ ID_CV
@ ID_PAL
@ ID_BR
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_SCR
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_VF
@ ID_ME
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
#define ID_NLA
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_HIDDEN_A
@ BONE_HIDDEN_P
@ BONE_TIPSEL
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
@ COLLECTION_COLOR_NONE
@ CONSTRAINT_TYPE_TRACKTO
@ CONSTRAINT_TYPE_PIVOT
@ CONSTRAINT_TYPE_CHILDOF
@ CONSTRAINT_TYPE_TRANSFORM
@ CONSTRAINT_TYPE_FOLLOWTRACK
@ CONSTRAINT_TYPE_OBJECTSOLVER
@ CONSTRAINT_TYPE_ARMATURE
@ CONSTRAINT_TYPE_LOCLIKE
@ CONSTRAINT_TYPE_SHRINKWRAP
@ CONSTRAINT_TYPE_MINMAX
@ CONSTRAINT_TYPE_ROTLIMIT
@ CONSTRAINT_TYPE_CAMERASOLVER
@ CONSTRAINT_TYPE_ROTLIKE
@ CONSTRAINT_TYPE_SPLINEIK
@ CONSTRAINT_TYPE_KINEMATIC
@ CONSTRAINT_TYPE_DISTLIMIT
@ CONSTRAINT_TYPE_TRANSLIKE
@ CONSTRAINT_TYPE_LOCLIMIT
@ CONSTRAINT_TYPE_CLAMPTO
@ CONSTRAINT_TYPE_LOCKTRACK
@ CONSTRAINT_TYPE_SIZELIMIT
@ CONSTRAINT_TYPE_ACTION
@ CONSTRAINT_TYPE_FOLLOWPATH
@ CONSTRAINT_TYPE_STRETCHTO
@ CONSTRAINT_TYPE_SIZELIKE
@ CONSTRAINT_TYPE_SAMEVOL
@ CONSTRAINT_TYPE_DAMPTRACK
@ CONSTRAINT_TYPE_TRANSFORM_CACHE
#define GPENCIL_EDIT_MODE(gpd)
@ eGpencilModifierType_Array
@ eGpencilModifierType_Noise
@ eGpencilModifierType_Mirror
@ eGpencilModifierType_Color
@ eGpencilModifierType_Multiply
@ eGpencilModifierType_Texture
@ eGpencilModifierType_Subdiv
@ eGpencilModifierType_Lattice
@ eGpencilModifierType_Opacity
@ eGpencilModifierType_Hook
@ eGpencilModifierType_Simplify
@ eGpencilModifierType_Shrinkwrap
@ eGpencilModifierType_WeightProximity
@ eGpencilModifierType_Armature
@ eGpencilModifierType_WeightAngle
@ eGpencilModifierType_Smooth
@ eGpencilModifierType_Tint
@ eGpencilModifierType_Time
@ eGpencilModifierType_Thick
@ eGpencilModifierType_Build
@ eGpencilModifierType_Offset
@ LAYERGROUP_COLOR_NONE
@ LAYER_COLLECTION_VISIBLE_VIEW_LAYER
@ VIEW_LAYER_RENDER
@ LAYER_COLLECTION_EXCLUDE
@ BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ LIGHTPROBE_TYPE_PLANE
@ LIGHTPROBE_TYPE_VOLUME
@ LIGHTPROBE_TYPE_SPHERE
@ OB_MODE_PARTICLE_EDIT
@ OB_MODE_EDIT
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_SPEAKER
@ OB_LATTICE
@ OB_MBALL
@ OB_EMPTY
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_TYPE_MAX
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_GPENCIL_LEGACY
@ OB_CURVES
@ OB_LIGHTPROBE
#define OB_DATA_SUPPORT_EDITMODE(_type)
@ OB_DUPLICOLLECTION
@ OB_EMPTY_IMAGE
@ TSE_BONE_COLLECTION
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_LIBRARY_OVERRIDE_OPERATION
@ TSE_MODIFIER_BASE
@ TSE_GP_LAYER
@ TSE_SEQUENCE_DUP
@ TSE_RNA_ARRAY_ELEM
@ TSE_SEQUENCE
@ TSE_GPENCIL_EFFECT
@ TSE_LINKED_NODE_TREE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_ANIM_DATA
@ TSE_LIBRARY_OVERRIDE
@ TSE_RNA_PROPERTY
@ TSE_LIBRARY_OVERRIDE_BASE
@ TSE_EBONE
@ TSE_NLA_TRACK
@ TSE_BONE
@ TSE_LINKED_PSYS
@ TSE_DEFGROUP_BASE
@ TSE_CONSTRAINT
@ TSE_SCENE_COLLECTION_BASE
@ TSE_SCENE_OBJECTS_BASE
@ TSE_R_LAYER_BASE
@ TSE_LAYER_COLLECTION
@ TSE_GREASE_PENCIL_NODE
@ TSE_SEQ_STRIP
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_LINKED_OB
@ TSE_NLA
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_DRIVER_BASE
@ TSE_NLA_ACTION
@ TSE_MODIFIER
@ TSE_BONE_COLLECTION_BASE
@ TSE_R_LAYER
@ TSE_RNA_STRUCT
@ TSE_POSE_BASE
@ TSE_DEFGROUP
@ TSE_DRAG_AFTER
@ TSE_SELECTED
@ TSE_HIGHLIGHTED_ICON
@ TSE_HIGHLIGHTED
@ TSE_SEARCHMATCH
@ TSE_DRAG_BEFORE
@ TSE_DRAG_ANY
@ TSE_ACTIVE
@ TSE_TEXTBUT
#define BASE_SELECTED(v3d, base)
@ SCE_OBJECT_MODE_LOCK
@ SEQ_TYPE_TRANSFORM
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_GLOW
@ SEQ_TYPE_COLORMIX
@ SEQ_TYPE_WIPE
@ SEQ_TYPE_META
@ SEQ_TYPE_OVERDROP
@ SEQ_TYPE_ALPHAUNDER
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_GAMCROSS
@ SEQ_TYPE_MULTICAM
@ SEQ_TYPE_MOVIECLIP
@ SEQ_TYPE_MUL
@ SEQ_TYPE_GAUSSIAN_BLUR
@ SEQ_TYPE_ADD
@ SEQ_TYPE_ALPHAOVER
@ SEQ_TYPE_TEXT
@ SEQ_TYPE_IMAGE
@ SEQ_TYPE_SUB
@ SEQ_TYPE_SPEED
@ SEQ_TYPE_COLOR
@ SEQ_TYPE_MOVIE
@ SEQ_TYPE_MASK
@ SEQ_TYPE_ADJUSTMENT
@ SO_LIB_OVERRIDE_VIEW_HIERARCHIES
@ SO_LIB_OVERRIDE_VIEW_PROPERTIES
@ SO_RESTRICT_HIDE
@ SO_RESTRICT_RENDER
@ SO_RESTRICT_INDIRECT_ONLY
@ SO_RESTRICT_VIEWPORT
@ SO_RESTRICT_ENABLE
@ SO_RESTRICT_HOLDOUT
@ SO_RESTRICT_SELECT
@ SO_SYNC_SELECT
@ SO_OVERRIDES_LIBRARY
@ SO_DATA_API
@ SO_LIBRARIES
@ SO_VIEW_LAYER
@ SO_SCENES
@ SO_ID_ORPHANS
@ TXT_ISMEM
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
@ V2D_PIXELOFS_X
@ V2D_PIXELOFS_Y
int ED_file_extension_icon(const char *path)
Definition filelist.cc:2862
bool ED_outliner_select_sync_is_dirty(const bContext *C)
void ED_outliner_select_sync_flag_outliners(const bContext *C)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
void immUniformColor4ubv(const unsigned char rgba[4])
void immEnd()
void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
void immUnbindProgram()
void immUniform2f(const char *name, float x, float y)
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
void immRecti(uint pos, int x1, int y1, int x2, int y2)
@ GPU_PRIM_LINES
@ GPU_PRIM_TRIS
@ GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:188
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
void GPU_scissor_get(int coords[4])
Definition gpu_state.cc:257
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
PropertyType
Definition RNA_types.hh:64
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_POINTER
Definition RNA_types.hh:70
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
void UI_but_flag_disable(uiBut *but, int flag)
void UI_but_disable(uiBut *but, const char *disabled_hint)
#define UI_UNIT_Y
@ UI_EMBOSS
@ UI_EMBOSS_NONE_OR_STATUS
void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
@ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
uiBut * uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const char *tip)
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void uiDefAutoButsArrayR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const int icon, const int x, const int y, const int tot_width, const int height)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_draw_roundbox_corner_set(int type)
void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_fn)
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, const char *name, const PointerRNA *ptr)
uiBut * uiDefIconButO(uiBlock *block, int type, const char *opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const char *tip)
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
void UI_block_draw(const bContext *C, uiBlock *block)
uiBut * uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, short *poin, float min, float max, const char *tip)
void UI_but_icon_indicator_set(uiBut *but, const char *string)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBut *but)
void UI_but_label_alpha_factor_set(uiBut *but, float alpha_factor)
@ UI_CNR_ALL
void UI_but_icon_indicator_color_set(uiBut *but, const uchar color[4])
#define UI_FSTYLE_WIDGET
uiBut * uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, const char *tip)
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_BUT
@ UI_BTYPE_TEXT
@ UI_BTYPE_LABEL
@ UI_BTYPE_ICON_TOGGLE_N
@ UI_BTYPE_ICON_TOGGLE
void UI_draw_roundbox_aa(const rctf *rect, bool filled, float rad, const float color[4])
void UI_block_end(const bContext *C, uiBlock *block)
void UI_but_flag_enable(uiBut *but, int flag)
uiBut * uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, const char *name, int icon, int x, int y, int width, int height)
@ UI_BUT_ICON_REVERSE
const PointerRNA * UI_but_context_ptr_get(const uiBut *but, const char *name, const StructRNA *type=nullptr)
@ UI_BUT_DRAG_LOCK
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
#define ICON_DEFAULT_HEIGHT
void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay, const int icon_indicator_number)
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4])
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
int UI_icon_from_library(const ID *id)
int UI_icon_from_object_mode(int mode)
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
void UI_GetThemeColor3fv(int colorid, float col[3])
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3])
@ TH_SELECT_ACTIVE
@ TH_ROW_ALTERNATE
@ TH_SELECT_HIGHLIGHT
@ TH_ACTIVE_OBJECT
@ TH_BACK
@ TH_EDITED_OBJECT
@ TH_SELECTED_OBJECT
@ TH_REDALERT
@ TH_MATCH
@ TH_TEXT
void UI_GetThemeColor3ubv(int colorid, unsigned char col[3])
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
bTheme * UI_GetTheme()
int BIFIconID
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
#define V2D_SCROLL_HEIGHT
Definition UI_view2d.hh:53
#define V2D_SCROLL_WIDTH
Definition UI_view2d.hh:54
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
Definition view2d.cc:1032
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
#define NC_ID
Definition WM_types.hh:362
#define ND_DATA
Definition WM_types.hh:475
#define ND_RENDER_OPTIONS
Definition WM_types.hh:402
#define NC_ANIMATION
Definition WM_types.hh:355
#define NC_SCENE
Definition WM_types.hh:345
#define ND_POSE
Definition WM_types.hh:425
#define NA_EDITED
Definition WM_types.hh:550
#define NC_MATERIAL
Definition WM_types.hh:347
#define NC_IMAGE
Definition WM_types.hh:351
#define NC_GPENCIL
Definition WM_types.hh:366
#define NC_TEXTURE
Definition WM_types.hh:348
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define ND_BONE_COLLECTION
Definition WM_types.hh:441
#define NA_RENAME
Definition WM_types.hh:554
@ KM_CTRL
Definition WM_types.hh:256
@ KM_SHIFT
Definition WM_types.hh:255
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_ANIMCHAN
Definition WM_types.hh:463
#define NC_SPACE
Definition WM_types.hh:359
#define NA_SELECTED
Definition WM_types.hh:555
#define ND_SPACE_OUTLINER
Definition WM_types.hh:493
void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep, const char *newnamep)
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child)
unsigned int U
Definition btGjkEpa3.h:78
constexpr bool is_empty() const
constexpr const char * c_str() const
virtual StringRefNull get_warning() const
local_group_size(16, 16) .push_constant(Type b
#define offsetof(t, d)
int len
bool ED_id_rename(Main &bmain, ID &id, blender::StringRefNull name)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uint col
#define GS(x)
Definition iris.cc:202
format
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
static void outliner_draw_warning_tree_element(uiBlock *block, const SpaceOutliner *space_outliner, StringRefNull warning_msg, const bool use_mode_column, const int te_ys)
static void outliner_collection_set_flag_recursive_fn(bContext *C, LayerCollection *layer_collection, Collection *collection, const char *propname)
static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner, ListBase *lb, int *width, int *height)
static void outliner_restrict_properties_enable_layer_collection_set(PointerRNA *layer_collection_ptr, PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *)
static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner, ListBase *lb, const TreeViewContext *tvc, int startx, int *starty)
static void outliner_draw_mode_column_toggle(uiBlock *block, TreeViewContext *tvc, TreeElement *te, const bool lock_object_modes)
static void outliner_draw_warning_column(uiBlock *block, const SpaceOutliner *space_outliner, const bool use_mode_column)
static StringRefNull outliner_draw_get_warning_tree_element(const SpaceOutliner &space_outliner, const TreeElement *te)
static bool is_object_data_in_editmode(const ID *id, const Object *obact)
static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
bool outliner_is_collection_tree_element(const TreeElement *te)
static void outliner_update_viewable_area(ARegion *region, SpaceOutliner *space_outliner, int tree_width, int tree_height, float right_column_width)
static bool subtree_contains_object(ListBase *lb)
static void outliner_draw_active_indicator(const float minx, const float miny, const float maxx, const float maxy, const float icon_color[4], const float icon_border[4])
static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *region, SpaceOutliner *space_outliner, ListBase *lb, RestrictPropertiesActive props_active_parent)
float outliner_right_columns_width(const SpaceOutliner *space_outliner)
static void outliner_draw_iconrow(bContext *C, uiBlock *block, const uiFontStyle *fstyle, const TreeViewContext *tvc, SpaceOutliner *space_outliner, ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, bool in_bone_hierarchy, const bool is_grease_pencil_node_hierarchy, MergedIconRow *merged)
static int outliner_data_api_buttons_start_x(int max_tree_width)
void outliner_collection_isolate_flag(Scene *scene, ViewLayer *view_layer, LayerCollection *layer_collection, Collection *collection, PropertyRNA *layer_or_collection_prop, const char *propname, const bool value)
static void namebutton_fn(bContext *C, void *tsep, char *oldname)
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
void outliner_item_mode_toggle(bContext *C, TreeViewContext *tvc, TreeElement *te, bool do_extend)
void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *space_outliner, ARegion *region)
static void outliner_draw_tree(bContext *C, uiBlock *block, const TreeViewContext *tvc, ARegion *region, SpaceOutliner *space_outliner, const float right_column_width, const bool use_mode_column, const bool use_warning_column, TreeElement **te_edit)
static bool outliner_but_identity_cmp_context_id_fn(const uiBut *a, const uiBut *b)
eOLDrawState tree_element_type_active_state_get(const bContext *C, const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
static void outliner_draw_tree_element(bContext *C, uiBlock *block, const uiFontStyle *fstyle, const TreeViewContext *tvc, ARegion *region, SpaceOutliner *space_outliner, TreeElement *te, bool draw_grayed_out, int startx, int *starty, const float restrict_column_width, TreeElement **te_edit)
static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
static void outliner_object_set_flag_recursive_fn(bContext *C, Base *base, Object *ob, const char *propname)
static void outliner_collection_set_flag_recursive(Scene *scene, ViewLayer *view_layer, LayerCollection *layer_collection, Collection *collection, PropertyRNA *layer_or_collection_prop, PropertyRNA *base_or_object_prop, const bool value)
void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
bool outliner_is_element_in_view(const TreeElement *te, const View2D *v2d)
static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
Collection * outliner_collection_from_tree_element(const TreeElement *te)
int tree_element_id_type_to_index(TreeElement *te)
static void outliner_layer_or_collection_pointer_create(Scene *scene, LayerCollection *layer_collection, Collection *collection, PointerRNA *ptr)
static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
static void outliner_draw_separator(ARegion *region, const int x)
static void outliner_set_subtree_coords(const TreeElement *te)
static int outliner_width(SpaceOutliner *space_outliner, int max_tree_width, float right_column_width)
static StringRefNull outliner_draw_get_warning_tree_element_subtree(const TreeElement *parent_te)
static void outliner_draw_highlights(uint pos, const ARegion *region, const SpaceOutliner *space_outliner, const float col_selection[4], const float col_active[4], const float col_highlight[4], const float col_searchmatch[4], int start_x, int *io_start_y)
static bool element_should_draw_faded(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem)
void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
TreeElementT * tree_element_cast(const TreeElement *te)
static void outliner_base_or_object_pointer_create(Scene *scene, ViewLayer *view_layer, Collection *collection, Object *ob, PointerRNA *ptr)
static void outliner_back(ARegion *region)
static bool tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, float alpha, const bool is_clickable, const int num_elements)
TreeElement * outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem)
static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *)
static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *)
static void outliner_draw_mode_column(uiBlock *block, TreeViewContext *tvc, SpaceOutliner *space_outliner)
static void outliner_restrict_properties_enable_collection_set(PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
static void restrictbutton_bone_select_fn(bContext *C, void *poin, void *poin2)
static void outliner_draw_overrides_rna_buts(uiBlock *block, const ARegion *region, const SpaceOutliner *space_outliner, const ListBase *lb, const int x)
static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *region, const float restrict_column_width, TreeElement *te)
static void restrictbutton_r_lay_fn(bContext *C, void *poin, void *)
static void outliner_draw_hierarchy_line(const uint pos, const int x, const int y1, const int y2, const bool draw_dashed)
void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height)
static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
static void outliner_draw_userbuts(uiBlock *block, const ARegion *region, const SpaceOutliner *space_outliner)
bool outliner_has_element_warnings(const SpaceOutliner &space_outliner)
static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
bool outliner_shows_mode_column(const SpaceOutliner &space_outliner)
static void outliner_draw_iconrow_doit(uiBlock *block, TreeElement *te, int xmax, int *offsx, int ys, float alpha_fac, const eOLDrawState active, const int num_elements)
static void outliner_draw_hierarchy_lines_recursive(uint pos, SpaceOutliner *space_outliner, ListBase *lb, const TreeViewContext *tvc, int startx, const uchar col[4], bool draw_grayed_out, int *starty)
static void outliner_draw_overrides_restrictbuts(Main *bmain, uiBlock *block, const ARegion *region, const SpaceOutliner *space_outliner, const ListBase *lb, const int x)
static void outliner_draw_struct_marks(ARegion *region, SpaceOutliner *space_outliner, ListBase *lb, int *starty)
static bool outliner_collection_is_isolated(Scene *scene, const LayerCollection *layer_collection_cmp, const Collection *collection_cmp, const bool value_cmp, const PropertyRNA *layer_or_collection_prop, LayerCollection *layer_collection, Collection *collection)
void draw_outliner(const bContext *C, bool do_rebuild)
static void restrictbutton_id_user_toggle(bContext *, void *poin, void *)
void tree_element_activate(bContext *C, const TreeViewContext *tvc, TreeElement *te, eOLSetState set, bool handle_all_types)
static void outliner_draw_rnabuts(uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex)
static void restrictbutton_recursive_ebone(bArmature *arm, EditBone *ebone_parent, int flag, bool set_flag)
static bool outliner_restrict_properties_collection_set(Scene *scene, TreeElement *te, PointerRNA *collection_ptr, PointerRNA *layer_collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
static BIFIconID tree_element_get_icon_from_id(const ID *id)
int ED_outliner_icon_from_id(const ID &id)
#define SEARCHING_OUTLINER(sov)
#define OL_RNA_COL_SPACEX
#define OL_RNA_COLX
#define OL_Y_OFFSET
#define OL_NAMEBUTTON
#define TREESTORE(a)
#define OL_RNA_COL_SIZEX
#define OL_TOG_USER_BUTS_USERS
#define TSELEM_OPEN(telm, sv)
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
bool RNA_struct_is_ID(const StructRNA *type)
PropertyType RNA_property_type(PropertyRNA *prop)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_struct_ui_icon(const StructRNA *type)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_property_boolean_get_default(PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
short flag
struct Object * object
char name[64]
ListBase childbase
struct Collection * collection
Collection_Runtime runtime
char name[64]
unsigned int flag
Definition DNA_ID.h:352
Definition DNA_ID.h:413
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
char name[66]
Definition DNA_ID.h:425
unsigned int session_uid
Definition DNA_ID.h:454
ListBase layer_collections
struct Collection * collection
char filepath[1024]
Definition DNA_ID.h:531
short type
void * first
ListBase objects
Definition BKE_main.hh:212
short transflag
struct Collection * instance_collection
ListBase modifiers
ListBase greasepencil_modifiers
struct PartDeflect * pd
char empty_drawtype
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
struct ToolSettings * toolsettings
char search_string[64]
short lib_override_view_mode
struct BLI_mempool * treestore
float icon_border_intensity
ListBase layer_collections
char name[64]
ListBase * edbo
bNodeTreeTypeHandle * typeinfo
struct Bone * bone
ThemeCollectionColor collection_color[8]
eOLDrawState active[INDEX_ID_MAX+OB_TYPE_MAX]
TreeElement * tree_element[INDEX_ID_MAX+OB_TYPE_MAX]
int num_elements[INDEX_ID_MAX+OB_TYPE_MAX]
std::unique_ptr< AbstractTreeElement > abstract_element
float ymax
float ymin
uint8_t modifier
Definition WM_types.hh:739
struct wmEvent * eventstate
static DynamicLibrary lib
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4126
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
uint8_t flag
Definition wm_window.cc:138