Blender V4.5
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
8
13#include "DNA_light_types.h"
16#include "DNA_object_types.h"
17#include "DNA_scene_types.h"
18#include "DNA_sequence_types.h"
19#include "DNA_text_types.h"
20
21#include "BLI_fileops.h"
22#include "BLI_listbase.h"
23#include "BLI_math_vector.h"
24#include "BLI_path_utils.hh"
25#include "BLI_string.h"
26#include "BLI_string_utils.hh"
27#include "BLI_utildefines.h"
28
29#include "BLT_translation.hh"
30
31#include "BKE_armature.hh"
32#include "BKE_context.hh"
33#include "BKE_curve.hh"
34#include "BKE_deform.hh"
35#include "BKE_gpencil_legacy.h"
36#include "BKE_grease_pencil.hh"
37#include "BKE_idtype.hh"
38#include "BKE_layer.hh"
39#include "BKE_lib_id.hh"
40#include "BKE_lib_override.hh"
41#include "BKE_library.hh"
42#include "BKE_main.hh"
43#include "BKE_main_namemap.hh"
44#include "BKE_modifier.hh"
45#include "BKE_node.hh"
46#include "BKE_object.hh"
47#include "BKE_particle.h"
48#include "BKE_report.hh"
49#include "BKE_scene.hh"
50
52#include "ANIM_keyframing.hh"
53
54#include "DEG_depsgraph.hh"
56
57#include "ED_armature.hh"
58#include "ED_fileselect.hh"
59#include "ED_id_management.hh"
60#include "ED_outliner.hh"
61#include "ED_screen.hh"
62#include "ED_undo.hh"
63
64#include "WM_api.hh"
65#include "WM_message.hh"
66#include "WM_types.hh"
67
68#include "GPU_immediate.hh"
69#include "GPU_state.hh"
70
71#include "UI_interface.hh"
72#include "UI_interface_icons.hh"
73#include "UI_resources.hh"
74#include "UI_view2d.hh"
75
76#include "RNA_access.hh"
77
78#include "outliner_intern.hh"
79#include "tree/tree_element.hh"
85#include "tree/tree_iterator.hh"
86
87namespace blender::ed::outliner {
88
89/* -------------------------------------------------------------------- */
92
93static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
94 ListBase *lb,
95 int *width,
96 int *height)
97{
98 LISTBASE_FOREACH (TreeElement *, te, lb) {
99 *width = std::max(*width, int(te->xend));
100 if (height != nullptr) {
101 *height += UI_UNIT_Y;
102 }
103
104 TreeStoreElem *tselem = TREESTORE(te);
105 if (TSELEM_OPEN(tselem, space_outliner)) {
106 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
107 }
108 else {
109 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
110 }
111 }
112}
113
114void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height)
115{
116 *r_width = 0;
117 *r_height = 0;
118 outliner_tree_dimensions_impl(space_outliner, &space_outliner->tree, r_width, r_height);
119}
120
124static bool is_object_data_in_editmode(const ID *id, const Object *obact)
125{
126 if (id == nullptr) {
127 return false;
128 }
129
130 const short id_type = GS(id->name);
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
137
138/* -------------------------------------------------------------------- */
141
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
183 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
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
197 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
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
214 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
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
230 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
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
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_discrete(&scene->id, &RNA_ObjectBase, base_iter);
302 }
303 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
305 C, scene, &ptr, base_or_object_prop, -1, BKE_scene_frame_get(scene), true);
306 }
307 }
308
309 /* We don't call RNA_property_update() due to performance, so we batch update them. */
310 if (ob) {
313 }
314 else {
317 }
318}
319
323static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
324{
325 Object *ob = static_cast<Object *>(poin);
326 const char *propname = static_cast<const char *>(poin2);
327 outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
328}
329
333static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
334{
335 Base *base = static_cast<Base *>(poin);
336 const char *propname = static_cast<const char *>(poin2);
337 outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
338}
339
342 LayerCollection *layer_collection,
343 Collection *collection,
345{
346 if (collection) {
347 *ptr = RNA_id_pointer_create(&collection->id);
348 }
349 else {
350 *ptr = RNA_pointer_create_discrete(&scene->id, &RNA_LayerCollection, layer_collection);
351 }
352}
353
356 Scene *scene, ViewLayer *view_layer, Collection *collection, Object *ob, PointerRNA *ptr)
357{
358 if (collection) {
360 }
361 else {
362 BKE_view_layer_synced_ensure(scene, view_layer);
363 Base *base = BKE_view_layer_base_find(view_layer, ob);
364 *ptr = RNA_pointer_create_discrete(&scene->id, &RNA_ObjectBase, base);
365 }
366}
367
368/* NOTE: Collection is only valid when we want to change the collection data, otherwise we get it
369 * from layer collection. Layer collection is valid whenever we are looking at a view layer. */
371 ViewLayer *view_layer,
372 LayerCollection *layer_collection,
373 Collection *collection,
374 PropertyRNA *layer_or_collection_prop,
375 PropertyRNA *base_or_object_prop,
376 const bool value)
377{
378 if (!layer_collection) {
379 return;
380 }
381
383 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
384 if (layer_or_collection_prop && !RNA_property_editable(&ptr, layer_or_collection_prop)) {
385 return;
386 }
387
388 RNA_property_boolean_set(&ptr, layer_or_collection_prop, value);
389
390 /* Set the same flag for the nested objects as well. */
391 if (base_or_object_prop && !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) {
392 /* NOTE: We can't use BKE_collection_object_cache_get()
393 * otherwise we would not take collection exclusion into account. */
394 LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
395
396 outliner_base_or_object_pointer_create(scene, view_layer, collection, cob->ob, &ptr);
397 if (!RNA_property_editable(&ptr, base_or_object_prop)) {
398 continue;
399 }
400
401 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
402
403 if (collection) {
405 }
406 }
407 }
408
409 /* Keep going recursively. */
410 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
411 LISTBASE_FOREACH (Link *, link, lb) {
412 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
413 Collection *collection_iter = layer_collection ?
414 (collection ? layer_collection_iter->collection : nullptr) :
415 ((CollectionChild *)link)->collection;
417 view_layer,
418 layer_collection_iter,
419 collection_iter,
420 layer_or_collection_prop,
421 base_or_object_prop,
422 value);
423 }
424
425 if (collection) {
427 }
428}
429
441 const LayerCollection *layer_collection_cmp,
442 const Collection *collection_cmp,
443 const bool value_cmp,
444 PropertyRNA *layer_or_collection_prop,
445 LayerCollection *layer_collection,
446 Collection *collection)
447{
449 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
450 const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
451 Collection *collection_ensure = collection ? collection : layer_collection->collection;
452 const Collection *collection_ensure_cmp = collection_cmp ? collection_cmp :
453 layer_collection_cmp->collection;
454
455 /* Exclude linked collections, otherwise toggling property won't reset the visibility for
456 * editable collections, see: #130579. */
457 if (layer_or_collection_prop && !RNA_property_editable(&ptr, layer_or_collection_prop)) {
458 return true;
459 }
460
461 if (collection_ensure->flag & COLLECTION_IS_MASTER) {
462 }
463 else if (collection_ensure == collection_ensure_cmp) {
464 }
465 else if (BKE_collection_has_collection(collection_ensure, (Collection *)collection_ensure_cmp) ||
466 BKE_collection_has_collection((Collection *)collection_ensure_cmp, collection_ensure))
467 {
468 /* This collection is either a parent or a child of the collection.
469 * We expect it to be set "visible" already. */
470 if (value != value_cmp) {
471 return false;
472 }
473 }
474 else {
475 /* This collection is neither a parent nor a child of the collection.
476 * We expect it to be "invisible". */
477 if (value == value_cmp) {
478 return false;
479 }
480 }
481
482 /* Keep going recursively. */
483 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
484 LISTBASE_FOREACH (Link *, link, lb) {
485 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
486 Collection *collection_iter = layer_collection ?
487 (collection ? layer_collection_iter->collection : nullptr) :
488 ((CollectionChild *)link)->collection;
489 if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
490 continue;
491 }
493 layer_collection_cmp,
494 collection_cmp,
495 value_cmp,
496 layer_or_collection_prop,
497 layer_collection_iter,
498 collection_iter))
499 {
500 return false;
501 }
502 }
503
504 return true;
505}
506
508 ViewLayer *view_layer,
509 LayerCollection *layer_collection,
510 Collection *collection,
511 PropertyRNA *layer_or_collection_prop,
512 const char *propname,
513 const bool value)
514{
516 const bool is_hide = strstr(propname, "hide_") || STREQ(propname, "exclude");
517
518 LayerCollection *top_layer_collection = layer_collection ?
519 static_cast<LayerCollection *>(
520 view_layer->layer_collections.first) :
521 nullptr;
522 Collection *top_collection = collection ? scene->master_collection : nullptr;
523
524 bool was_isolated = (value == is_hide);
525 was_isolated &= outliner_collection_is_isolated(scene,
526 layer_collection,
527 collection,
528 !is_hide,
529 layer_or_collection_prop,
530 top_layer_collection,
531 top_collection);
532
533 if (was_isolated) {
534 const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
535 /* Make every collection go back to its default "visibility" state. */
537 view_layer,
538 top_layer_collection,
539 top_collection,
540 layer_or_collection_prop,
541 nullptr,
542 default_value);
543 return;
544 }
545
546 /* Make every collection "invisible". */
548 view_layer,
549 top_layer_collection,
550 top_collection,
551 layer_or_collection_prop,
552 nullptr,
553 is_hide);
554
555 /* Make this collection and its children collections the only "visible". */
557 view_layer,
558 layer_collection,
559 collection,
560 layer_or_collection_prop,
561 nullptr,
562 !is_hide);
563
564 /* Make this collection direct parents also "visible". */
565 if (layer_collection) {
566 LayerCollection *lc_parent = layer_collection;
567 LISTBASE_FOREACH (LayerCollection *, lc_iter, &top_layer_collection->layer_collections) {
568 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
569 lc_parent = lc_iter;
570 break;
571 }
572 }
573
574 while (lc_parent != layer_collection) {
576 scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
577 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
578
579 LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
580 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
581 lc_parent = lc_iter;
582 break;
583 }
584 }
585 }
586 }
587 else {
588 CollectionParent *parent;
589 Collection *child = collection;
590 while ((parent = static_cast<CollectionParent *>(child->runtime.parents.first))) {
591 if (parent->collection->flag & COLLECTION_IS_MASTER) {
592 break;
593 }
595 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
596 child = parent->collection;
597 }
598 }
599}
600
602 LayerCollection *layer_collection,
603 Collection *collection,
604 const char *propname)
605{
606 Main *bmain = CTX_data_main(C);
607 wmWindow *win = CTX_wm_window(C);
608 Scene *scene = CTX_data_scene(C);
609 ViewLayer *view_layer = CTX_data_view_layer(C);
610
611 bool do_isolate = (win->eventstate->modifier & KM_CTRL);
612 bool extend = (win->eventstate->modifier & KM_SHIFT);
613
614 if (!ELEM(true, do_isolate, extend)) {
615 return;
616 }
617
618 /* Create PointerRNA and PropertyRNA for either Collection or LayerCollection. */
619 ID *id = collection ? &collection->id : &scene->id;
620 StructRNA *struct_rna = collection ? &RNA_Collection : &RNA_LayerCollection;
621 void *data = collection ? (void *)collection : (void *)layer_collection;
622
624 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
625 PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
626 const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
627
628 PropertyRNA *base_or_object_prop = nullptr;
629 if (layer_collection != nullptr) {
630 /* If we are toggling Layer collections we still want to change the properties of the base
631 * or the objects. If we have a matching property, toggle it as well, it can be nullptr. */
632 struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
633 base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname);
634 }
635
636 if (extend) {
638 view_layer,
639 layer_collection,
640 collection,
641 layer_or_collection_prop,
642 base_or_object_prop,
643 value);
644 }
645 else {
647 view_layer,
648 layer_collection,
649 collection,
650 layer_or_collection_prop,
651 propname,
652 value);
653 }
654
655 /* We don't call RNA_property_update() due to performance, so we batch update them. */
658}
659
665 void *poin,
666 void *poin2)
667{
668 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
669 const char *propname = static_cast<const char *>(poin2);
670 outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
671}
672
677static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
678{
679 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
680 const char *propname = static_cast<const char *>(poin2);
682 C, layer_collection, layer_collection->collection, propname);
683}
684
689static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
690{
691 Collection *collection = static_cast<Collection *>(poin);
692 const char *propname = static_cast<const char *>(poin2);
693 outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
694}
695
696static void namebutton_fn(bContext *C, void *tsep, char *oldname)
697{
698 Main *bmain = CTX_data_main(C);
699 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
701 BLI_mempool *ts = space_outliner->treestore;
702 TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep);
703
704 const char *undo_str = nullptr;
705
706 /* Unfortunately at this point, the name of the ID has already been set to its new value. Revert
707 * it to its old name, to be able to use the generic 'rename' function for IDs.
708 *
709 * NOTE: While utterly inelegant, performances are not really a concern here, so this is an
710 * acceptable solution for now. */
711 auto id_rename_helper = [bmain, tselem, oldname]() -> bool {
712 std::string new_name = tselem->id->name + 2;
713 BLI_strncpy(tselem->id->name + 2, oldname, sizeof(tselem->id->name) - 2);
714 return ED_id_rename(*bmain, *tselem->id, new_name);
715 };
716
717 if (ts && tselem) {
718 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
719
720 if (ELEM(tselem->type, TSE_SOME_ID, TSE_LINKED_NODE_TREE)) {
721 if (id_rename_helper()) {
722 undo_str = "Rename Data-Block";
723 }
724
725 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
726
727 switch (GS(tselem->id->name)) {
728 case ID_MA:
730 break;
731 case ID_TE:
733 break;
734 case ID_IM:
736 break;
737 case ID_SCE:
739 break;
740 default:
741 break;
742 }
744
745 /* Check the library target exists */
746 if (te->idcode == ID_LI) {
747 Library *lib = (Library *)tselem->id;
748 char expanded[FILE_MAX];
749
750 BKE_library_filepath_set(bmain, lib, lib->filepath);
751
752 STRNCPY(expanded, lib->filepath);
753 BLI_path_abs(expanded, BKE_main_blendfile_path(bmain));
754 if (!BLI_exists(expanded)) {
756 RPT_ERROR,
757 "Library path '%s' does not exist, correct this before saving",
758 expanded);
759 }
760 else if (lib->id.tag & ID_TAG_MISSING) {
762 RPT_INFO,
763 "Library path '%s' is now valid, please reload the library",
764 expanded);
765 lib->id.tag &= ~ID_TAG_MISSING;
766 }
767 }
768
770 }
771 else {
772 switch (tselem->type) {
773 case TSE_DEFGROUP: {
774 Object *ob = (Object *)tselem->id;
775 bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata);
777 WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
779 undo_str = "Rename Vertex Group";
780 break;
781 }
782 case TSE_NLA_ACTION: {
783 /* The #tselem->id is a #bAction. */
784 if (id_rename_helper()) {
785 undo_str = "Rename Data-Block";
786 }
787 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
789 break;
790 }
791 case TSE_NLA_TRACK: {
793 undo_str = "Rename NLA Track";
794 break;
795 }
796 case TSE_MODIFIER: {
799 undo_str = "Rename Modifier";
800 break;
801 }
802 case TSE_EBONE: {
803 bArmature *arm = (bArmature *)tselem->id;
804 if (arm->edbo) {
805 EditBone *ebone = static_cast<EditBone *>(te->directdata);
806 char newname[sizeof(ebone->name)];
807
808 /* restore bone name */
809 STRNCPY(newname, ebone->name);
810 STRNCPY(ebone->name, oldname);
811 ED_armature_bone_rename(bmain, arm, oldname, newname);
812 WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
815 undo_str = "Rename Edit Bone";
816 }
817 break;
818 }
819
820 case TSE_BONE: {
821 TreeViewContext tvc;
823
824 bArmature *arm = (bArmature *)tselem->id;
825 Bone *bone = static_cast<Bone *>(te->directdata);
826 char newname[sizeof(bone->name)];
827
828 /* always make current object active */
830
831 /* restore bone name */
832 STRNCPY(newname, bone->name);
833 STRNCPY(bone->name, oldname);
834 ED_armature_bone_rename(bmain, arm, oldname, newname);
835 WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
838 undo_str = "Rename Bone";
839 break;
840 }
841 case TSE_POSE_CHANNEL: {
842 TreeViewContext tvc;
844
845 Object *ob = (Object *)tselem->id;
846 bArmature *arm = (bArmature *)ob->data;
847 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
848 char newname[sizeof(pchan->name)];
849
850 /* always make current pose-bone active */
852
854
855 /* restore bone name */
856 STRNCPY(newname, pchan->name);
857 STRNCPY(pchan->name, oldname);
858 ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname);
859 WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
863 undo_str = "Rename Pose Bone";
864 break;
865 }
866 case TSE_GP_LAYER: {
867 bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
868 bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
869
870 /* always make layer active */
872
873 /* XXX: name needs translation stuff. */
875 &gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
876
877 WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, GPencilLayer, info);
881 undo_str = "Rename Grease Pencil Layer";
882 break;
883 }
885 GreasePencil &grease_pencil = *(GreasePencil *)tselem->id;
888
889 /* The node already has the new name set. To properly rename the node, we need to first
890 * store the new name, restore the old name in the node, and then call the rename
891 * function. */
892 std::string new_name(node.name());
893 node.set_name(oldname);
894 grease_pencil.rename_node(*bmain, node, new_name);
897 undo_str = "Rename Grease Pencil Drawing";
898 break;
899 }
900 case TSE_R_LAYER: {
901 Scene *scene = (Scene *)tselem->id;
902 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
903
904 /* Restore old name. */
905 char newname[sizeof(view_layer->name)];
906 STRNCPY(newname, view_layer->name);
907 STRNCPY(view_layer->name, oldname);
908
909 /* Rename, preserving animation and compositing data. */
910 BKE_view_layer_rename(bmain, scene, view_layer, newname);
911 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
914 undo_str = "Rename View Layer";
915 break;
916 }
918 /* The #tselem->id is a #Collection, not a #LayerCollection */
919 if (id_rename_helper()) {
920 undo_str = "Rename Data-Block";
921 }
922 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
925 break;
926 }
927
928 case TSE_BONE_COLLECTION: {
929 bArmature *arm = (bArmature *)tselem->id;
930 BoneCollection *bcoll = static_cast<BoneCollection *>(te->directdata);
931
932 ANIM_armature_bonecoll_name_set(arm, bcoll, bcoll->name);
933 WM_msg_publish_rna_prop(mbus, &arm->id, bcoll, BoneCollection, name);
936 undo_str = "Rename Bone Collection";
937 break;
938 }
939
940 case TSE_ACTION_SLOT: {
942 undo_str = "Rename Action Slot";
943 break;
944 }
945 }
946 }
947 tselem->flag &= ~TSE_TEXTBUT;
948 }
949
950 if (undo_str) {
951 ED_undo_push(C, undo_str);
952 }
953}
954
967
968/* We don't care about the value of the property
969 * but whether the property should be active or grayed out. */
987
989 PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
990{
991 if (props_active->collection_hide_render) {
993 collection_ptr, props->collection_hide_render);
994 if (!props_active->collection_hide_render) {
995 props_active->layer_collection_holdout = false;
996 props_active->layer_collection_indirect_only = false;
997 props_active->object_hide_render = false;
998 props_active->modifier_show_render = false;
999 props_active->constraint_enable = false;
1000 }
1001 }
1002
1003 if (props_active->collection_hide_viewport) {
1005 collection_ptr, props->collection_hide_viewport);
1006 if (!props_active->collection_hide_viewport) {
1007 props_active->collection_hide_select = false;
1008 props_active->object_hide_select = false;
1009 props_active->layer_collection_hide_viewport = false;
1010 props_active->object_hide_viewport = false;
1011 props_active->base_hide_viewport = false;
1012 props_active->modifier_show_viewport = false;
1013 props_active->constraint_enable = false;
1014 }
1015 }
1016
1017 if (props_active->collection_hide_select) {
1019 collection_ptr, props->collection_hide_select);
1020 if (!props_active->collection_hide_select) {
1021 props_active->object_hide_select = false;
1022 }
1023 }
1024}
1025
1027 PointerRNA *layer_collection_ptr,
1028 PointerRNA *collection_ptr,
1029 RestrictProperties *props,
1030 RestrictPropertiesActive *props_active)
1031{
1032 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1033
1034 if (props_active->layer_collection_holdout) {
1036 layer_collection_ptr, props->layer_collection_holdout);
1037 }
1038
1039 if (props_active->layer_collection_indirect_only) {
1041 layer_collection_ptr, props->layer_collection_indirect_only);
1042 }
1043
1044 if (props_active->layer_collection_hide_viewport) {
1046 layer_collection_ptr, props->layer_collection_hide_viewport);
1047
1048 if (!props_active->layer_collection_hide_viewport) {
1049 props_active->base_hide_viewport = false;
1050 props_active->collection_hide_select = false;
1051 props_active->object_hide_select = false;
1052 }
1053 }
1054
1055 if (props_active->layer_collection_exclude) {
1057 layer_collection_ptr, props->layer_collection_exclude);
1058
1059 if (!props_active->layer_collection_exclude) {
1060 props_active->collection_hide_viewport = false;
1061 props_active->collection_hide_select = false;
1062 props_active->collection_hide_render = false;
1063 props_active->layer_collection_hide_viewport = false;
1064 props_active->layer_collection_holdout = false;
1065 props_active->layer_collection_indirect_only = false;
1066 }
1067 }
1068}
1069
1071 TreeElement *te,
1072 PointerRNA *collection_ptr,
1073 PointerRNA *layer_collection_ptr,
1074 RestrictProperties *props,
1075 RestrictPropertiesActive *props_active)
1076{
1077 TreeStoreElem *tselem = TREESTORE(te);
1078 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1079 static_cast<LayerCollection *>(te->directdata) :
1080 nullptr;
1082
1083 if (collection->flag & COLLECTION_IS_MASTER) {
1084 return false;
1085 }
1086
1087 /* Create the PointerRNA. */
1088 *collection_ptr = RNA_id_pointer_create(&collection->id);
1089 if (layer_collection != nullptr) {
1090 *layer_collection_ptr = RNA_pointer_create_discrete(
1091 &scene->id, &RNA_LayerCollection, layer_collection);
1092 }
1093
1094 /* Update the restriction column values for the collection children. */
1095 if (layer_collection) {
1097 layer_collection_ptr, collection_ptr, props, props_active);
1098 }
1099 else {
1100 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1101 }
1102 return true;
1103}
1104
1106 Scene *scene,
1107 ViewLayer *view_layer,
1108 ARegion *region,
1109 SpaceOutliner *space_outliner,
1110 ListBase *lb,
1111 RestrictPropertiesActive props_active_parent)
1112{
1113 /* Get RNA properties (once for speed). */
1114 static RestrictProperties props = {false};
1115 if (!props.initialized) {
1116 props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport");
1117 props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
1118 props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
1119 props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport");
1121 "hide_viewport");
1122 props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
1123 props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
1124 props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection,
1125 "exclude");
1126 props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection,
1127 "holdout");
1129 "indirect_only");
1131 "hide_viewport");
1132 props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
1133 props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
1134
1135 props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
1136
1137 props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide");
1138
1139 props.initialized = true;
1140 }
1141
1142 struct {
1143 int enable;
1144 int select;
1145 int hide;
1146 int viewport;
1147 int render;
1148 int indirect_only;
1149 int holdout;
1150 } restrict_offsets = {0};
1151 int restrict_column_offset = 0;
1152
1153 /* This will determine the order of drawing from RIGHT to LEFT. */
1154 if (space_outliner->outlinevis == SO_VIEW_LAYER) {
1155 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1156 restrict_offsets.indirect_only = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1157 }
1158 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1159 restrict_offsets.holdout = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1160 }
1161 }
1162 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1163 restrict_offsets.render = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1164 }
1165 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1166 restrict_offsets.viewport = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1167 }
1168 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1169 restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1170 }
1171 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1172 restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1173 }
1174 if (space_outliner->outlinevis == SO_VIEW_LAYER &&
1175 space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)
1176 {
1177 restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1178 }
1179
1180 BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
1181 outliner_right_columns_width(space_outliner));
1182
1183 /* Create buttons. */
1184 uiBut *bt;
1185
1186 LISTBASE_FOREACH (TreeElement *, te, lb) {
1187 TreeStoreElem *tselem = TREESTORE(te);
1188 RestrictPropertiesActive props_active = props_active_parent;
1189
1190 if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
1191 if (tselem->type == TSE_R_LAYER &&
1192 ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER))
1193 {
1194 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1195 /* View layer render toggle. */
1196 ViewLayer *layer = static_cast<ViewLayer *>(te->directdata);
1197
1198 bt = uiDefIconButBitS(block,
1201 0,
1202 ICON_RESTRICT_RENDER_OFF,
1203 int(region->v2d.cur.xmax - restrict_offsets.render),
1204 te->ys,
1205 UI_UNIT_X,
1206 UI_UNIT_Y,
1207 &layer->flag,
1208 0,
1209 0,
1210 TIP_("Use view layer for rendering"));
1211 UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
1214 }
1215 }
1216 else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) &&
1217 (te->flag & TE_CHILD_NOT_IN_COLLECTION))
1218 {
1219 /* Don't show restrict columns for children that are not directly inside the collection. */
1220 }
1221 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1222 Object *ob = (Object *)tselem->id;
1224
1225 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1226 BKE_view_layer_synced_ensure(scene, view_layer);
1227 Base *base = (te->directdata) ? (Base *)te->directdata :
1228 BKE_view_layer_base_find(view_layer, ob);
1229 if (base) {
1230 PointerRNA base_ptr = RNA_pointer_create_discrete(&scene->id, &RNA_ObjectBase, base);
1231 bt = uiDefIconButR_prop(block,
1233 0,
1234 ICON_NONE,
1235 int(region->v2d.cur.xmax - restrict_offsets.hide),
1236 te->ys,
1237 UI_UNIT_X,
1238 UI_UNIT_Y,
1239 &base_ptr,
1240 props.base_hide_viewport,
1241 -1,
1242 0,
1243 0,
1244 TIP_("Temporarily hide in viewport\n"
1245 " \u2022 Shift to set children"));
1247 bt, outliner__base_set_flag_recursive_fn, base, (void *)"hide_viewport");
1249 if (!props_active.base_hide_viewport) {
1251 }
1252 }
1253 }
1254
1255 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1256 bt = uiDefIconButR_prop(block,
1258 0,
1259 ICON_NONE,
1260 int(region->v2d.cur.xmax - restrict_offsets.select),
1261 te->ys,
1262 UI_UNIT_X,
1263 UI_UNIT_Y,
1264 &ptr,
1265 props.object_hide_select,
1266 -1,
1267 0,
1268 0,
1269 TIP_("Disable selection in viewport\n"
1270 " \u2022 Shift to set children"));
1271 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_select");
1273 if (!props_active.object_hide_select) {
1275 }
1276 }
1277
1278 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1279 bt = uiDefIconButR_prop(block,
1281 0,
1282 ICON_NONE,
1283 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1284 te->ys,
1285 UI_UNIT_X,
1286 UI_UNIT_Y,
1287 &ptr,
1289 -1,
1290 0,
1291 0,
1292 TIP_("Globally disable in viewports\n"
1293 " \u2022 Shift to set children"));
1294 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (void *)"hide_viewport");
1296 if (!props_active.object_hide_viewport) {
1298 }
1299 }
1300
1301 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1302 bt = uiDefIconButR_prop(block,
1304 0,
1305 ICON_NONE,
1306 int(region->v2d.cur.xmax - restrict_offsets.render),
1307 te->ys,
1308 UI_UNIT_X,
1309 UI_UNIT_Y,
1310 &ptr,
1311 props.object_hide_render,
1312 -1,
1313 0,
1314 0,
1315 TIP_("Globally disable in renders\n"
1316 " \u2022 Shift to set children"));
1317 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_render");
1319 if (!props_active.object_hide_render) {
1321 }
1322 }
1323 }
1324 else if (tselem->type == TSE_CONSTRAINT) {
1325 bConstraint *con = (bConstraint *)te->directdata;
1326
1327 PointerRNA ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Constraint, con);
1328
1329 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1330 bt = uiDefIconButR_prop(block,
1332 0,
1333 ICON_NONE,
1334 int(region->v2d.cur.xmax - restrict_offsets.hide),
1335 te->ys,
1336 UI_UNIT_X,
1337 UI_UNIT_Y,
1338 &ptr,
1339 props.constraint_enable,
1340 -1,
1341 0,
1342 0,
1343 nullptr);
1345 if (!props_active.constraint_enable) {
1347 }
1348 }
1349 }
1350 else if (tselem->type == TSE_MODIFIER) {
1351 ModifierData *md = (ModifierData *)te->directdata;
1352
1353 PointerRNA ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Modifier, md);
1354
1355 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1356 bt = uiDefIconButR_prop(block,
1358 0,
1359 ICON_NONE,
1360 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1361 te->ys,
1362 UI_UNIT_X,
1363 UI_UNIT_Y,
1364 &ptr,
1366 -1,
1367 0,
1368 0,
1369 std::nullopt);
1371 if (!props_active.modifier_show_viewport) {
1373 }
1374 }
1375
1376 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1377 bt = uiDefIconButR_prop(block,
1379 0,
1380 ICON_NONE,
1381 int(region->v2d.cur.xmax - restrict_offsets.render),
1382 te->ys,
1383 UI_UNIT_X,
1384 UI_UNIT_Y,
1385 &ptr,
1387 -1,
1388 0,
1389 0,
1390 std::nullopt);
1392 if (!props_active.modifier_show_render) {
1394 }
1395 }
1396 }
1397 else if (tselem->type == TSE_POSE_CHANNEL) {
1398 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
1399 Bone *bone = pchan->bone;
1400 Object *ob = (Object *)tselem->id;
1401 bArmature *arm = static_cast<bArmature *>(ob->data);
1402
1403 PointerRNA ptr = RNA_pointer_create_discrete(&arm->id, &RNA_Bone, bone);
1404
1405 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1406 bt = uiDefIconButR_prop(block,
1408 0,
1409 ICON_NONE,
1410 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1411 te->ys,
1412 UI_UNIT_X,
1413 UI_UNIT_Y,
1414 &ptr,
1415 props.bone_hide_viewport,
1416 -1,
1417 0,
1418 0,
1419 TIP_("Restrict visibility in the 3D View\n"
1420 " \u2022 Shift to set children"));
1424 }
1425
1426 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1427 bt = uiDefIconButBitI(block,
1430 0,
1431 ICON_RESTRICT_SELECT_OFF,
1432 int(region->v2d.cur.xmax - restrict_offsets.select),
1433 te->ys,
1434 UI_UNIT_X,
1435 UI_UNIT_Y,
1436 &(bone->flag),
1437 0,
1438 0,
1439 TIP_("Restrict selection in the 3D View\n"
1440 " \u2022 Shift to set children"));
1444 }
1445 }
1446 else if (tselem->type == TSE_EBONE) {
1447 bArmature *arm = (bArmature *)tselem->id;
1448 EditBone *ebone = (EditBone *)te->directdata;
1449
1450 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1451 bt = uiDefIconButBitI(block,
1454 0,
1455 ICON_RESTRICT_VIEW_OFF,
1456 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1457 te->ys,
1458 UI_UNIT_X,
1459 UI_UNIT_Y,
1460 &(ebone->flag),
1461 0,
1462 0,
1463 TIP_("Restrict visibility in the 3D View\n"
1464 " \u2022 Shift to set children"));
1468 }
1469
1470 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1471 bt = uiDefIconButBitI(block,
1474 0,
1475 ICON_RESTRICT_SELECT_OFF,
1476 int(region->v2d.cur.xmax - restrict_offsets.select),
1477 te->ys,
1478 UI_UNIT_X,
1479 UI_UNIT_Y,
1480 &(ebone->flag),
1481 0,
1482 0,
1483 TIP_("Restrict selection in the 3D View\n"
1484 " \u2022 Shift to set children"));
1488 }
1489 }
1490 else if (tselem->type == TSE_GP_LAYER) {
1491 ID *id = tselem->id;
1492 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
1493
1494 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1495 bt = uiDefIconButBitS(block,
1498 0,
1499 ICON_HIDE_OFF,
1500 int(region->v2d.cur.xmax - restrict_offsets.hide),
1501 te->ys,
1502 UI_UNIT_X,
1503 UI_UNIT_Y,
1504 &gpl->flag,
1505 0,
1506 0,
1507 TIP_("Restrict visibility in the 3D View"));
1511 }
1512
1513 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1514 bt = uiDefIconButBitS(block,
1517 0,
1518 ICON_UNLOCKED,
1519 int(region->v2d.cur.xmax - restrict_offsets.select),
1520 te->ys,
1521 UI_UNIT_X,
1522 UI_UNIT_Y,
1523 &gpl->flag,
1524 0,
1525 0,
1526 TIP_("Restrict editing of strokes and keyframes in this layer"));
1529 }
1530 }
1531 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
1535 PropertyRNA *hide_prop;
1536 if (node.is_layer()) {
1537 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_GreasePencilLayer, &node);
1538 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayer, "hide");
1539 }
1540 else if (node.is_group()) {
1541 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_GreasePencilLayerGroup, &node);
1542 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayerGroup, "hide");
1543 }
1544
1545 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1546 bt = uiDefIconButR_prop(block,
1548 0,
1549 0,
1550 int(region->v2d.cur.xmax - restrict_offsets.hide),
1551 te->ys,
1552 UI_UNIT_X,
1553 UI_UNIT_Y,
1554 &ptr,
1555 hide_prop,
1556 -1,
1557 0,
1558 0,
1559 std::nullopt);
1561 if (node.parent_group() && !node.parent_group()->is_visible()) {
1563 }
1564 }
1565 }
1567 PointerRNA collection_ptr;
1568 PointerRNA layer_collection_ptr;
1569
1571 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active))
1572 {
1573
1574 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1575 static_cast<LayerCollection *>(te->directdata) :
1576 nullptr;
1578
1579 if (layer_collection != nullptr) {
1580 if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
1581 bt = uiDefIconButR_prop(block,
1583 0,
1584 ICON_NONE,
1585 int(region->v2d.cur.xmax) - restrict_offsets.enable,
1586 te->ys,
1587 UI_UNIT_X,
1588 UI_UNIT_Y,
1589 &layer_collection_ptr,
1591 -1,
1592 0,
1593 0,
1594 std::nullopt);
1595 UI_but_func_set(bt,
1597 layer_collection,
1598 (char *)"exclude");
1600 }
1601
1602 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1603 bt = uiDefIconButR_prop(block,
1605 0,
1606 ICON_NONE,
1607 int(region->v2d.cur.xmax - restrict_offsets.hide),
1608 te->ys,
1609 UI_UNIT_X,
1610 UI_UNIT_Y,
1611 &layer_collection_ptr,
1613 -1,
1614 0,
1615 0,
1616 TIP_("Temporarily hide in viewport\n"
1617 " \u2022 Ctrl to isolate collection\n"
1618 " \u2022 Shift to set inside collections and objects"));
1619 UI_but_func_set(bt,
1621 layer_collection,
1622 (char *)"hide_viewport");
1624 if (!props_active.layer_collection_hide_viewport) {
1626 }
1627 }
1628
1629 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1630 bt = uiDefIconButR_prop(block,
1632 0,
1633 ICON_NONE,
1634 int(region->v2d.cur.xmax - restrict_offsets.holdout),
1635 te->ys,
1636 UI_UNIT_X,
1637 UI_UNIT_Y,
1638 &layer_collection_ptr,
1640 -1,
1641 0,
1642 0,
1643 TIP_("Mask out objects in collection from view layer\n"
1644 " \u2022 Ctrl to isolate collection\n"
1645 " \u2022 Shift to set inside collections"));
1646 UI_but_func_set(bt,
1648 layer_collection,
1649 (char *)"holdout");
1651 if (!props_active.layer_collection_holdout) {
1653 }
1654 }
1655
1656 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1657 bt = uiDefIconButR_prop(
1658 block,
1660 0,
1661 ICON_NONE,
1662 int(region->v2d.cur.xmax - restrict_offsets.indirect_only),
1663 te->ys,
1664 UI_UNIT_X,
1665 UI_UNIT_Y,
1666 &layer_collection_ptr,
1668 -1,
1669 0,
1670 0,
1671 TIP_("Objects in collection only contribute indirectly (through shadows and "
1672 "reflections) in the view layer\n"
1673 " \u2022 Ctrl to isolate collection\n"
1674 " \u2022 Shift to set inside collections"));
1675 UI_but_func_set(bt,
1677 layer_collection,
1678 (char *)"indirect_only");
1680 if (props_active.layer_collection_holdout ||
1681 !props_active.layer_collection_indirect_only)
1682 {
1684 }
1685 }
1686 }
1687
1688 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1689 bt = uiDefIconButR_prop(block,
1691 0,
1692 ICON_NONE,
1693 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1694 te->ys,
1695 UI_UNIT_X,
1696 UI_UNIT_Y,
1697 &collection_ptr,
1699 -1,
1700 0,
1701 0,
1702 TIP_("Globally disable in viewports\n"
1703 " \u2022 Ctrl to isolate collection\n"
1704 " \u2022 Shift to set inside collections and objects"));
1705 if (layer_collection != nullptr) {
1706 UI_but_func_set(bt,
1708 layer_collection,
1709 (char *)"hide_viewport");
1710 }
1711 else {
1712 UI_but_func_set(bt,
1714 collection,
1715 (char *)"hide_viewport");
1716 }
1718 if (!props_active.collection_hide_viewport) {
1720 }
1721 }
1722
1723 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1724 bt = uiDefIconButR_prop(block,
1726 0,
1727 ICON_NONE,
1728 int(region->v2d.cur.xmax - restrict_offsets.render),
1729 te->ys,
1730 UI_UNIT_X,
1731 UI_UNIT_Y,
1732 &collection_ptr,
1734 -1,
1735 0,
1736 0,
1737 TIP_("Globally disable in renders\n"
1738 " \u2022 Ctrl to isolate collection\n"
1739 " \u2022 Shift to set inside collections and objects"));
1740 if (layer_collection != nullptr) {
1741 UI_but_func_set(bt,
1743 layer_collection,
1744 (char *)"hide_render");
1745 }
1746 else {
1748 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_render");
1749 }
1751 if (!props_active.collection_hide_render) {
1753 }
1754 }
1755
1756 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1757 bt = uiDefIconButR_prop(block,
1759 0,
1760 ICON_NONE,
1761 int(region->v2d.cur.xmax - restrict_offsets.select),
1762 te->ys,
1763 UI_UNIT_X,
1764 UI_UNIT_Y,
1765 &collection_ptr,
1767 -1,
1768 0,
1769 0,
1770 TIP_("Disable selection in viewport\n"
1771 " \u2022 Ctrl to isolate collection\n"
1772 " \u2022 Shift to set inside collections and objects"));
1773 if (layer_collection != nullptr) {
1774 UI_but_func_set(bt,
1776 layer_collection,
1777 (char *)"hide_select");
1778 }
1779 else {
1781 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_select");
1782 }
1784 if (!props_active.collection_hide_select) {
1786 }
1787 }
1788 }
1789 }
1790 }
1792 PointerRNA collection_ptr;
1793 PointerRNA layer_collection_ptr;
1795 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active);
1796 }
1797
1798 if (TSELEM_OPEN(tselem, space_outliner)) {
1800 block, scene, view_layer, region, space_outliner, &te->subtree, props_active);
1801 }
1802 }
1803}
1804
1806 const ARegion *region,
1807 const SpaceOutliner *space_outliner)
1808{
1809 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
1810 if (!outliner_is_element_in_view(te, &region->v2d)) {
1811 return;
1812 }
1813
1814 const TreeStoreElem *tselem = TREESTORE(te);
1815 ID *id = tselem->id;
1816
1817 if (tselem->type != TSE_SOME_ID || id->tag & ID_TAG_EXTRAUSER) {
1818 return;
1819 }
1820
1821 uiBut *bt;
1822 std::optional<StringRef> tip;
1823 const int real_users = id->us - ID_FAKE_USERS(id);
1824 const bool has_fake_user = id->flag & ID_FLAG_FAKEUSER;
1825 const bool is_linked = ID_IS_LINKED(id);
1826 const bool is_object = GS(id->name) == ID_OB;
1827 char overlay[5];
1828 BLI_str_format_integer_unit(overlay, id->us);
1829
1830 if (is_object) {
1831 bt = uiDefBut(block,
1833 0,
1834 overlay,
1835 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1836 te->ys,
1837 UI_UNIT_X,
1838 UI_UNIT_Y,
1839 nullptr,
1840 0.0,
1841 0.0,
1842 TIP_("Number of users"));
1843 }
1844 else {
1845
1846 if (has_fake_user) {
1847 tip = is_linked ? TIP_("Item is protected from deletion") :
1848 TIP_("Click to remove protection from deletion");
1849 }
1850 else {
1851 if (real_users) {
1852 tip = is_linked ? TIP_("Item is not protected from deletion") :
1853 TIP_("Click to add protection from deletion");
1854 }
1855 else {
1856 tip = is_linked ?
1857 TIP_("Item has no users and will be removed") :
1858 TIP_("Item has no users and will be removed.\nClick to protect from deletion");
1859 }
1860 }
1861
1862 bt = uiDefIconButBitS(block,
1865 1,
1866 ICON_FAKE_USER_OFF,
1867 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1868 te->ys,
1869 UI_UNIT_X,
1870 UI_UNIT_Y,
1871 &id->flag,
1872 0,
1873 0,
1874 tip);
1875
1876 if (is_linked) {
1878 }
1879 else {
1881 /* Allow _inaccurate_ dragging over multiple toggles. */
1883 }
1884
1885 if (!real_users && !has_fake_user) {
1886 uchar overlay_color[4];
1887 UI_GetThemeColor4ubv(TH_REDALERT, overlay_color);
1888 UI_but_icon_indicator_color_set(bt, overlay_color);
1889 }
1890 UI_but_icon_indicator_set(bt, overlay);
1891 }
1892 });
1893}
1894
1896 const ARegion *region,
1897 const SpaceOutliner *space_outliner,
1898 const ListBase *lb,
1899 const int x)
1900{
1901 const float pad_x = 2.0f * UI_SCALE_FAC;
1902 const float pad_y = 0.5f * U.pixelsize;
1903 const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x);
1904 const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y);
1905
1906 LISTBASE_FOREACH (const TreeElement *, te, lb) {
1907 const TreeStoreElem *tselem = TREESTORE(te);
1908 if (TSELEM_OPEN(tselem, space_outliner)) {
1909 outliner_draw_overrides_rna_buts(block, region, space_outliner, &te->subtree, x);
1910 }
1911
1912 if (!outliner_is_element_in_view(te, &region->v2d)) {
1913 continue;
1914 }
1916 te);
1917 if (!override_elem) {
1918 continue;
1919 }
1920
1921 if (!override_elem->is_rna_path_valid) {
1922 uiBut *but = uiDefBut(block,
1924 0,
1925 override_elem->rna_path,
1926 x + pad_x,
1927 te->ys + pad_y,
1928 item_max_width,
1929 item_height,
1930 nullptr,
1931 0.0f,
1932 0.0f,
1933 "");
1935 continue;
1936 }
1937
1938 if (const TreeElementOverridesPropertyOperation *override_op_elem =
1940 {
1941 StringRefNull op_label = override_op_elem->get_override_operation_label();
1942 if (!op_label.is_empty()) {
1943 uiDefBut(block,
1945 0,
1946 op_label,
1947 x + pad_x,
1948 te->ys + pad_y,
1949 item_max_width,
1950 item_height,
1951 nullptr,
1952 0,
1953 0,
1954 "");
1955 continue;
1956 }
1957 }
1958
1959 PointerRNA *ptr = &override_elem->override_rna_ptr;
1960 PropertyRNA *prop = &override_elem->override_rna_prop;
1961 const PropertyType prop_type = RNA_property_type(prop);
1962
1963 uiBut *auto_but = uiDefAutoButR(block,
1964 ptr,
1965 prop,
1966 -1,
1967 (prop_type == PROP_ENUM) ? std::nullopt : std::optional(""),
1968 ICON_NONE,
1969 x + pad_x,
1970 te->ys + pad_y,
1971 item_max_width,
1972 item_height);
1973 /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons
1974 * need to be handled. */
1975 if (auto_but) {
1976 continue;
1977 }
1978
1979 if (!auto_but) {
1980 /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension
1981 * arrays? */
1983 block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height);
1984 }
1985 }
1986}
1987
1989{
1990 const std::optional<int64_t> session_uid_a = UI_but_context_int_get(a, "session_uid");
1991 const std::optional<int64_t> session_uid_b = UI_but_context_int_get(b, "session_uid");
1992 if (!session_uid_a || !session_uid_b) {
1993 return false;
1994 }
1995 /* Using session UID to compare is safer than using the pointer. */
1996 return session_uid_a == session_uid_b;
1997}
1998
2000 uiBlock *block,
2001 const ARegion *region,
2002 const SpaceOutliner *space_outliner,
2003 const ListBase *lb,
2004 const int x)
2005{
2006 LISTBASE_FOREACH (const TreeElement *, te, lb) {
2007 const TreeStoreElem *tselem = TREESTORE(te);
2008 if (TSELEM_OPEN(tselem, space_outliner)) {
2009 outliner_draw_overrides_restrictbuts(bmain, block, region, space_outliner, &te->subtree, x);
2010 }
2011
2012 if (!outliner_is_element_in_view(te, &region->v2d)) {
2013 continue;
2014 }
2016 if (!te_id) {
2017 continue;
2018 }
2019
2020 ID &id = te_id->get_ID();
2021 if (ID_IS_LINKED(&id)) {
2022 continue;
2023 }
2024 if (!ID_IS_OVERRIDE_LIBRARY(&id)) {
2025 /* Some items may not be liboverrides, e.g. the root item for all linked libraries (see
2026 * #TreeDisplayOverrideLibraryHierarchies::build_tree). */
2027 continue;
2028 }
2029
2030 const bool is_system_override = BKE_lib_override_library_is_system_defined(bmain, &id);
2031 const BIFIconID icon = is_system_override ? ICON_LIBRARY_DATA_OVERRIDE_NONEDITABLE :
2032 ICON_LIBRARY_DATA_OVERRIDE;
2033 uiBut *but = uiDefIconButO(block,
2035 "ED_OT_lib_id_override_editable_toggle",
2037 icon,
2038 x,
2039 te->ys,
2040 UI_UNIT_X,
2041 UI_UNIT_Y,
2042 "");
2043 UI_but_context_int_set(block, but, "session_uid", id.session_uid);
2046 }
2047}
2048
2049static void outliner_draw_separator(ARegion *region, const int x)
2050{
2051 View2D *v2d = &region->v2d;
2052
2053 GPU_line_width(1.0f);
2054
2058
2060
2061 immVertex2f(pos, x, v2d->cur.ymax);
2062 immVertex2f(pos, x, v2d->cur.ymin);
2063
2064 immEnd();
2065
2067}
2068
2070 ARegion *region,
2071 SpaceOutliner *space_outliner,
2072 int sizex)
2073{
2075 PropertyRNA *prop;
2076
2077 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2078 TreeStoreElem *tselem = TREESTORE(te);
2079
2080 if (!outliner_is_element_in_view(te, &region->v2d)) {
2081 return;
2082 }
2083
2085 ptr = te_rna_prop->get_pointer_rna();
2086 prop = te_rna_prop->get_property_rna();
2087
2088 if (!TSELEM_OPEN(tselem, space_outliner)) {
2089 if (RNA_property_type(prop) == PROP_POINTER) {
2090 uiBut *but = uiDefAutoButR(block,
2091 &ptr,
2092 prop,
2093 -1,
2094 "",
2095 ICON_NONE,
2096 sizex,
2097 te->ys,
2099 UI_UNIT_Y - 1);
2101 }
2102 else if (RNA_property_type(prop) == PROP_ENUM) {
2103 uiDefAutoButR(block,
2104 &ptr,
2105 prop,
2106 -1,
2107 std::nullopt,
2108 ICON_NONE,
2109 sizex,
2110 te->ys,
2112 UI_UNIT_Y - 1);
2113 }
2114 else {
2115 uiDefAutoButR(block,
2116 &ptr,
2117 prop,
2118 -1,
2119 "",
2120 ICON_NONE,
2121 sizex,
2122 te->ys,
2124 UI_UNIT_Y - 1);
2125 }
2126 }
2127 }
2128 else if (TreeElementRNAArrayElement *te_rna_array_elem =
2130 {
2131 ptr = te_rna_array_elem->get_pointer_rna();
2132 prop = te_rna_array_elem->get_property_rna();
2133
2134 uiDefAutoButR(block,
2135 &ptr,
2136 prop,
2137 te->index,
2138 "",
2139 ICON_NONE,
2140 sizex,
2141 te->ys,
2143 UI_UNIT_Y - 1);
2144 }
2145 });
2146}
2147
2148static void outliner_buttons(const bContext *C,
2149 uiBlock *block,
2150 ARegion *region,
2151 const float restrict_column_width,
2152 TreeElement *te)
2153{
2154 uiBut *bt;
2155 TreeStoreElem *tselem;
2156 int spx, dx, len;
2157
2158 tselem = TREESTORE(te);
2159
2160 BLI_assert(tselem->flag & TSE_TEXTBUT);
2161 /* If we add support to rename Sequence, need change this. */
2162
2163 if (tselem->type == TSE_EBONE) {
2164 len = sizeof(EditBone::name);
2165 }
2166 else if (tselem->type == TSE_MODIFIER) {
2167 len = sizeof(ModifierData::name);
2168 }
2169 else if (tselem->id && GS(tselem->id->name) == ID_LI) {
2170 len = sizeof(Library::filepath);
2171 }
2172 else {
2173 len = MAX_ID_NAME - 2;
2174 }
2175
2176 spx = te->xs + 1.8f * UI_UNIT_X;
2177 dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X);
2178
2179 bt = uiDefBut(block,
2182 "",
2183 spx,
2184 te->ys,
2185 dx,
2186 UI_UNIT_Y - 1,
2187 (void *)te->name,
2188 1.0,
2189 float(len),
2190 "");
2191 /* Handle undo through the #template_id_cb set below. Default undo handling from the button
2192 * code (see #ui_apply_but_undo) would not work here, as the new name is not yet applied to the
2193 * ID. */
2196
2197 /* Returns false if button got removed. */
2198 if (false == UI_but_active_only(C, region, block, bt)) {
2199 tselem->flag &= ~TSE_TEXTBUT;
2200
2201 /* Bad! (notifier within draw) without this, we don't get a refresh. */
2203 }
2204}
2205
2206static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void * /*arg2*/)
2207{
2208 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2209 TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin;
2210 TreeViewContext tvc;
2212
2213 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
2214 if (!te) {
2215 return;
2216 }
2217
2218 /* Check that the item is actually an object. */
2219 BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
2220
2221 Object *ob = (Object *)tselem->id;
2222 const bool object_data_shared = (ob->data == tvc.obact->data);
2223
2224 wmWindow *win = CTX_wm_window(C);
2225 const bool do_extend = (win->eventstate->modifier & KM_CTRL) && !object_data_shared;
2226 outliner_item_mode_toggle(C, tvc, te, do_extend);
2227}
2228
2229/* Draw icons for adding and removing objects from the current interaction mode. */
2231 const TreeViewContext &tvc,
2232 TreeElement *te,
2233 const bool lock_object_modes)
2234{
2235 TreeStoreElem *tselem = TREESTORE(te);
2236 if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
2237 return;
2238 }
2239
2240 Object *ob = (Object *)tselem->id;
2241 Object *ob_active = tvc.obact;
2242
2243 /* Not all objects support particle systems. */
2244 if (ob_active->mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) {
2245 return;
2246 }
2247
2248 /* Only for objects with the same type. */
2249 if (ob->type != ob_active->type) {
2250 return;
2251 }
2252
2253 if (ob->mode == OB_MODE_OBJECT && BKE_object_is_in_editmode(ob)) {
2254 /* Another object has our (shared) data in edit mode, so nothing we can change. */
2255 uiBut *but = uiDefIconBut(block,
2257 0,
2258 UI_icon_from_object_mode(ob_active->mode),
2259 0,
2260 te->ys,
2261 UI_UNIT_X,
2262 UI_UNIT_Y,
2263 nullptr,
2264 0.0,
2265 0.0,
2266 TIP_("Another object has this shared data in edit mode"));
2268 return;
2269 }
2270
2271 bool draw_active_icon = ob->mode == ob_active->mode;
2272
2273 /* When not locking object modes, objects can remain in non-object modes. For modes that do not
2274 * allow multi-object editing, these other objects should still show be viewed as not in the
2275 * mode. Otherwise multiple objects show the same mode icon in the outliner even though only
2276 * one object is actually editable in the mode. */
2277 if (!lock_object_modes && ob != ob_active && !(tvc.ob_edit || tvc.ob_pose)) {
2278 draw_active_icon = false;
2279 }
2280
2281 const bool object_data_shared = (ob->data == ob_active->data);
2282 draw_active_icon = draw_active_icon || object_data_shared;
2283
2284 int icon;
2285 StringRef tip;
2286 if (draw_active_icon) {
2287 icon = UI_icon_from_object_mode(ob_active->mode);
2288 tip = object_data_shared ? TIP_("Change the object in the current mode") :
2289 TIP_("Remove from the current mode");
2290 }
2291 else {
2292 icon = ICON_DOT;
2293 tip = TIP_(
2294 "Change the object in the current mode\n"
2295 " \u2022 Ctrl to add to the current mode");
2296 }
2298 uiBut *but = uiDefIconBut(block,
2300 0,
2301 icon,
2302 0,
2303 te->ys,
2304 UI_UNIT_X,
2305 UI_UNIT_Y,
2306 nullptr,
2307 0.0,
2308 0.0,
2309 tip);
2310 UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
2312 /* Mode toggling handles its own undo state because undo steps need to be grouped. */
2314
2315 if (!ID_IS_EDITABLE(&ob->id) ||
2318 {
2319 UI_but_disable(but, "Can't edit library or non-editable override data");
2320 }
2321}
2322
2324 TreeViewContext &tvc,
2325 SpaceOutliner *space_outliner)
2326{
2327 const bool lock_object_modes = tvc.scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
2328
2329 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2330 if (tvc.obact && tvc.obact->mode != OB_MODE_OBJECT) {
2331 outliner_draw_mode_column_toggle(block, tvc, te, lock_object_modes);
2332 }
2333 });
2334}
2335
2337{
2338 LISTBASE_FOREACH (const TreeElement *, sub_te, &parent_te->subtree) {
2340 StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2341
2342 if (!warning_msg.is_empty()) {
2343 return warning_msg;
2344 }
2345
2347 if (!warning_msg.is_empty()) {
2348 return warning_msg;
2349 }
2350 }
2351
2352 return "";
2353}
2354
2356 const TreeElement *te)
2357{
2359 const StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2360
2361 if (!warning_msg.is_empty()) {
2362 return warning_msg;
2363 }
2364
2365 /* If given element has no warning, recursively try to display the first sub-element's warning.
2366 */
2367 if (!TSELEM_OPEN(te->store_elem, &space_outliner)) {
2369 }
2370
2371 return "";
2372}
2373
2375 const SpaceOutliner *space_outliner,
2376 const StringRef warning_msg,
2377 const bool use_mode_column,
2378 const int te_ys)
2379{
2380 /* Move the warnings a unit left in view layer mode. */
2381 const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
2382 UI_UNIT_X :
2383 0;
2384
2386 uiBut *but = uiDefIconBut(block,
2388 0,
2389 ICON_ERROR,
2390 mode_column_offset,
2391 te_ys,
2392 UI_UNIT_X,
2393 UI_UNIT_Y,
2394 nullptr,
2395 0.0,
2396 0.0,
2397 warning_msg);
2398 /* No need for undo here, this is a pure info widget. */
2400}
2401
2403 const SpaceOutliner *space_outliner,
2404 const bool use_mode_column)
2405{
2406 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
2407 /* Get warning for this element, or if there is none and the element is collapsed, the first
2408 * warning in the collapsed sub-tree. */
2409 StringRefNull warning_msg = outliner_draw_get_warning_tree_element(*space_outliner, te);
2410
2411 if (!warning_msg.is_empty()) {
2413 block, space_outliner, warning_msg, use_mode_column, te->ys);
2414 }
2415 });
2416}
2417
2419
2420/* -------------------------------------------------------------------- */
2423
2425{
2426 if (GS(id->name) == ID_OB) {
2427 const Object *ob = (Object *)id;
2428 switch (ob->type) {
2429 case OB_LAMP:
2430 return ICON_OUTLINER_OB_LIGHT;
2431 case OB_MESH:
2432 return ICON_OUTLINER_OB_MESH;
2433 case OB_CAMERA:
2434 return ICON_OUTLINER_OB_CAMERA;
2435 case OB_CURVES_LEGACY:
2436 return ICON_OUTLINER_OB_CURVE;
2437 case OB_MBALL:
2438 return ICON_OUTLINER_OB_META;
2439 case OB_LATTICE:
2440 return ICON_OUTLINER_OB_LATTICE;
2441 case OB_ARMATURE:
2442 return ICON_OUTLINER_OB_ARMATURE;
2443 case OB_FONT:
2444 return ICON_OUTLINER_OB_FONT;
2445 case OB_SURF:
2446 return ICON_OUTLINER_OB_SURFACE;
2447 case OB_SPEAKER:
2448 return ICON_OUTLINER_OB_SPEAKER;
2449 case OB_LIGHTPROBE:
2450 return ICON_OUTLINER_OB_LIGHTPROBE;
2451 case OB_CURVES:
2452 return ICON_OUTLINER_OB_CURVES;
2453 case OB_POINTCLOUD:
2454 return ICON_OUTLINER_OB_POINTCLOUD;
2455 case OB_VOLUME:
2456 return ICON_OUTLINER_OB_VOLUME;
2457 case OB_EMPTY:
2459 return ICON_OUTLINER_OB_GROUP_INSTANCE;
2460 }
2461 else if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
2462 return ICON_OUTLINER_OB_IMAGE;
2463 }
2464 else if (ob->pd && ob->pd->forcefield) {
2465 return ICON_OUTLINER_OB_FORCE_FIELD;
2466 }
2467 else {
2468 return ICON_OUTLINER_OB_EMPTY;
2469 }
2470 case OB_GREASE_PENCIL:
2471 return ICON_OUTLINER_OB_GREASEPENCIL;
2472 }
2473
2474 return ICON_NONE;
2475 }
2476
2477 /* TODO(sergey): Casting to short here just to handle ID_NLA which is
2478 * NOT inside of IDType enum.
2479 */
2480 switch (short(GS(id->name))) {
2481 case ID_SCE:
2482 return ICON_SCENE_DATA;
2483 case ID_ME:
2484 return ICON_OUTLINER_DATA_MESH;
2485 case ID_CU_LEGACY: {
2486 const Curve *cu = (Curve *)id;
2487 switch (cu->ob_type) {
2488 case OB_FONT:
2489 return ICON_OUTLINER_DATA_FONT;
2490 case OB_SURF:
2491 return ICON_OUTLINER_DATA_SURFACE;
2492 default:
2493 return ICON_OUTLINER_DATA_CURVE;
2494 }
2495 break;
2496 }
2497 case ID_MB:
2498 return ICON_OUTLINER_DATA_META;
2499 case ID_LT:
2500 return ICON_OUTLINER_DATA_LATTICE;
2501 case ID_LA: {
2502 const Light *la = (Light *)id;
2503 switch (la->type) {
2504 case LA_LOCAL:
2505 return ICON_LIGHT_POINT;
2506 case LA_SUN:
2507 return ICON_LIGHT_SUN;
2508 case LA_SPOT:
2509 return ICON_LIGHT_SPOT;
2510 case LA_AREA:
2511 return ICON_LIGHT_AREA;
2512 default:
2513 return ICON_OUTLINER_DATA_LIGHT;
2514 }
2515 }
2516 case ID_MA:
2517 return ICON_MATERIAL_DATA;
2518 case ID_TE:
2519 return ICON_TEXTURE_DATA;
2520 case ID_IM:
2521 return ICON_IMAGE_DATA;
2522 case ID_SPK:
2523 case ID_SO:
2524 return ICON_OUTLINER_DATA_SPEAKER;
2525 case ID_AR:
2526 return ICON_OUTLINER_DATA_ARMATURE;
2527 case ID_CA:
2528 return ICON_OUTLINER_DATA_CAMERA;
2529 case ID_KE:
2530 return ICON_SHAPEKEY_DATA;
2531 case ID_WO:
2532 return ICON_WORLD_DATA;
2533 case ID_AC:
2534 return ICON_ACTION;
2535 case ID_NLA:
2536 return ICON_NLA;
2537 case ID_TXT: {
2538 const Text *text = (Text *)id;
2539 if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
2540 return ICON_FILE_TEXT;
2541 }
2542 /* Helps distinguish text-based formats like the file-browser does. */
2543 return ED_file_extension_icon(text->filepath);
2544 }
2545 case ID_GR:
2546 return ICON_OUTLINER_COLLECTION;
2547 case ID_CV:
2548 return ICON_OUTLINER_DATA_CURVES;
2549 case ID_PT:
2550 return ICON_OUTLINER_DATA_POINTCLOUD;
2551 case ID_VO:
2552 return ICON_OUTLINER_DATA_VOLUME;
2553 case ID_LI:
2554 if (id->tag & ID_TAG_MISSING) {
2555 return ICON_LIBRARY_DATA_BROKEN;
2556 }
2557 else if (((Library *)id)->runtime->parent) {
2558 return ICON_LIBRARY_DATA_INDIRECT;
2559 }
2560 else {
2561 return ICON_LIBRARY_DATA_DIRECT;
2562 }
2563 case ID_LS:
2564 return ICON_LINE_DATA;
2565 case ID_GP:
2566 case ID_GD_LEGACY:
2567 return ICON_OUTLINER_DATA_GREASEPENCIL;
2568 case ID_LP: {
2569 const LightProbe *lp = (LightProbe *)id;
2570 switch (lp->type) {
2572 return ICON_LIGHTPROBE_SPHERE;
2574 return ICON_LIGHTPROBE_PLANE;
2576 return ICON_LIGHTPROBE_VOLUME;
2577 default:
2578 return ICON_LIGHTPROBE_SPHERE;
2579 }
2580 }
2581 case ID_BR:
2582 return ICON_BRUSH_DATA;
2583 case ID_SCR:
2584 case ID_WS:
2585 return ICON_WORKSPACE;
2586 case ID_MSK:
2587 return ICON_MOD_MASK;
2588 case ID_NT: {
2589 const bNodeTree *ntree = (bNodeTree *)id;
2590 const bke::bNodeTreeType *ntreetype = ntree->typeinfo;
2591 return ntreetype->ui_icon;
2592 }
2593 case ID_MC:
2594 return ICON_SEQUENCE;
2595 case ID_PC:
2596 return ICON_CURVE_BEZCURVE;
2597 case ID_PA:
2598 return ICON_PARTICLES;
2599 case ID_PAL:
2600 return ICON_COLOR;
2601 case ID_VF:
2602 return ICON_FILE_FONT;
2603 default:
2604 return ICON_NONE;
2605 }
2606}
2607
2609{
2610 TreeElementIcon data = {nullptr};
2611
2612 if (tselem->type != TSE_SOME_ID) {
2613 switch (tselem->type) {
2614 case TSE_ACTION_SLOT:
2615 data.icon = ICON_ACTION_SLOT;
2616 break;
2617 case TSE_ANIM_DATA:
2618 data.icon = ICON_ANIM_DATA; /* XXX */
2619 break;
2620 case TSE_NLA:
2621 data.icon = ICON_NLA;
2622 break;
2623 case TSE_NLA_TRACK:
2624 data.icon = ICON_NLA; /* XXX */
2625 break;
2626 case TSE_NLA_ACTION:
2627 data.icon = ICON_ACTION;
2628 break;
2629 case TSE_DRIVER_BASE:
2630 data.icon = ICON_DRIVER;
2631 break;
2632 case TSE_DEFGROUP_BASE:
2633 data.icon = ICON_GROUP_VERTEX;
2634 break;
2635 case TSE_DEFGROUP:
2636 data.icon = ICON_GROUP_VERTEX;
2637 break;
2638 case TSE_BONE:
2639 case TSE_EBONE:
2640 data.icon = ICON_BONE_DATA;
2641 break;
2643 data.icon = ICON_CONSTRAINT;
2644 data.drag_id = tselem->id;
2645 break;
2646 case TSE_CONSTRAINT: {
2647 bConstraint *con = static_cast<bConstraint *>(te->directdata);
2648 data.drag_id = tselem->id;
2649 switch ((eBConstraint_Types)con->type) {
2651 data.icon = ICON_CON_CAMERASOLVER;
2652 break;
2654 data.icon = ICON_CON_FOLLOWTRACK;
2655 break;
2657 data.icon = ICON_CON_OBJECTSOLVER;
2658 break;
2660 data.icon = ICON_CON_LOCLIKE;
2661 break;
2663 data.icon = ICON_CON_ROTLIKE;
2664 break;
2666 data.icon = ICON_CON_SIZELIKE;
2667 break;
2669 data.icon = ICON_CON_TRANSLIKE;
2670 break;
2672 data.icon = ICON_CON_DISTLIMIT;
2673 break;
2675 data.icon = ICON_CON_LOCLIMIT;
2676 break;
2678 data.icon = ICON_CON_ROTLIMIT;
2679 break;
2681 data.icon = ICON_CON_SIZELIMIT;
2682 break;
2684 data.icon = ICON_CON_SAMEVOL;
2685 break;
2687 data.icon = ICON_CON_TRANSFORM;
2688 break;
2690 data.icon = ICON_CON_TRANSFORM_CACHE;
2691 break;
2693 data.icon = ICON_CON_CLAMPTO;
2694 break;
2696 data.icon = ICON_CON_TRACKTO;
2697 break;
2699 data.icon = ICON_CON_KINEMATIC;
2700 break;
2702 data.icon = ICON_CON_LOCKTRACK;
2703 break;
2705 data.icon = ICON_CON_SPLINEIK;
2706 break;
2708 data.icon = ICON_CON_STRETCHTO;
2709 break;
2711 data.icon = ICON_CON_TRACKTO;
2712 break;
2714 data.icon = ICON_CON_ACTION;
2715 break;
2717 data.icon = ICON_CON_ARMATURE;
2718 break;
2720 data.icon = ICON_CON_CHILDOF;
2721 break;
2723 data.icon = ICON_CON_FLOOR;
2724 break;
2726 data.icon = ICON_CON_FOLLOWPATH;
2727 break;
2729 data.icon = ICON_CON_PIVOT;
2730 break;
2732 data.icon = ICON_CON_SHRINKWRAP;
2733 break;
2734
2735 default:
2736 data.icon = ICON_DOT;
2737 break;
2738 }
2739 break;
2740 }
2741 case TSE_MODIFIER_BASE:
2742 data.icon = ICON_MODIFIER_DATA;
2743 data.drag_id = tselem->id;
2744 break;
2747 data.icon = tree_element_get_icon_from_id(&base_te->id);
2748 break;
2749 }
2751 data.icon = ICON_LIBRARY_DATA_OVERRIDE;
2752 break;
2753 case TSE_LINKED_OB:
2754 data.icon = ICON_OBJECT_DATA;
2755 break;
2756 case TSE_LINKED_PSYS:
2757 data.icon = ICON_PARTICLES;
2758 break;
2759 case TSE_MODIFIER: {
2760 Object *ob = (Object *)tselem->id;
2761 data.drag_id = tselem->id;
2762
2763 ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr));
2764 if (const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(ModifierType(md->type)))
2765 {
2766 data.icon = modifier_type->icon;
2767 }
2768 else {
2769 data.icon = ICON_DOT;
2770 }
2771 break;
2772 }
2774 data.icon = ICON_NODETREE;
2775 break;
2776 case TSE_POSE_BASE:
2777 data.icon = ICON_ARMATURE_DATA;
2778 break;
2779 case TSE_POSE_CHANNEL:
2780 data.icon = ICON_BONE_DATA;
2781 break;
2782 case TSE_R_LAYER_BASE:
2783 data.icon = ICON_RENDERLAYERS;
2784 break;
2786 data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE;
2787 break;
2788 case TSE_R_LAYER:
2789 data.icon = ICON_RENDER_RESULT;
2790 break;
2793 data.icon = ICON_GROUP_BONE;
2794 break;
2795 case TSE_STRIP: {
2797 switch (te_strip->get_strip_type()) {
2798 case STRIP_TYPE_SCENE:
2799 data.icon = ICON_SCENE_DATA;
2800 break;
2802 data.icon = ICON_TRACKER;
2803 break;
2804 case STRIP_TYPE_MASK:
2805 data.icon = ICON_MOD_MASK;
2806 break;
2807 case STRIP_TYPE_MOVIE:
2808 data.icon = ICON_FILE_MOVIE;
2809 break;
2811 data.icon = ICON_SOUND;
2812 break;
2813 case STRIP_TYPE_IMAGE:
2814 data.icon = ICON_FILE_IMAGE;
2815 break;
2816 case STRIP_TYPE_COLOR:
2818 data.icon = ICON_COLOR;
2819 break;
2820 case STRIP_TYPE_TEXT:
2821 data.icon = ICON_FONT_DATA;
2822 break;
2823 case STRIP_TYPE_ADD:
2824 case STRIP_TYPE_SUB:
2825 case STRIP_TYPE_MUL:
2831 case STRIP_TYPE_SPEED:
2832 case STRIP_TYPE_GLOW:
2834 data.icon = ICON_SHADERFX;
2835 break;
2836 case STRIP_TYPE_CROSS:
2838 case STRIP_TYPE_WIPE:
2839 data.icon = ICON_ARROW_LEFTRIGHT;
2840 break;
2841 case STRIP_TYPE_META:
2842 data.icon = ICON_SEQ_STRIP_META;
2843 break;
2844 default:
2845 data.icon = ICON_DOT;
2846 break;
2847 }
2848 break;
2849 }
2850 case TSE_STRIP_DATA:
2851 data.icon = ICON_LIBRARY_DATA_DIRECT;
2852 break;
2853 case TSE_STRIP_DUP:
2854 data.icon = ICON_SEQ_STRIP_DUPLICATE;
2855 break;
2856 case TSE_RNA_STRUCT: {
2858 const PointerRNA &ptr = te_rna_struct->get_pointer_rna();
2859
2860 if (RNA_struct_is_ID(ptr.type)) {
2861 data.drag_id = static_cast<ID *>(ptr.data);
2862 data.icon = RNA_struct_ui_icon(ptr.type);
2863 }
2864 else {
2865 data.icon = RNA_struct_ui_icon(ptr.type);
2866 }
2867 break;
2868 }
2873 if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
2874 data.drag_id = tselem->id;
2875 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2876 }
2877
2878 data.icon = ICON_OUTLINER_COLLECTION;
2879 break;
2880 }
2881 case TSE_GP_LAYER: {
2882 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2883 break;
2884 }
2888 if (node.is_layer()) {
2889 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2890 }
2891 else if (node.is_group()) {
2892 const bke::greasepencil::LayerGroup &group = node.as_group();
2893
2894 data.icon = ICON_GREASEPENCIL_LAYER_GROUP;
2895 if (group.color_tag != LAYERGROUP_COLOR_NONE) {
2896 data.icon = ICON_LAYERGROUP_COLOR_01 + group.color_tag;
2897 }
2898 }
2899 break;
2900 }
2902 case TSE_GPENCIL_EFFECT:
2903 data.drag_id = tselem->id;
2904 data.icon = ICON_SHADERFX;
2905 break;
2906 default:
2907 data.icon = ICON_DOT;
2908 break;
2909 }
2910 }
2911 else if (tselem->id) {
2912 data.drag_id = tselem->id;
2913 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2914 data.icon = tree_element_get_icon_from_id(tselem->id);
2915 }
2916
2917 if (!te->abstract_element) {
2918 /* Pass */
2919 }
2920 else if (auto icon = te->abstract_element->get_icon()) {
2921 data.icon = *icon;
2922 }
2923
2924 return data;
2925}
2926
2930static bool tselem_draw_icon(uiBlock *block,
2931 int xmax,
2932 float x,
2933 float y,
2934 TreeStoreElem *tselem,
2935 TreeElement *te,
2936 float alpha,
2937 const bool is_clickable,
2938 const int num_elements)
2939{
2941 if (data.icon == 0) {
2942 return false;
2943 }
2944
2945 const bool is_collection = outliner_is_collection_tree_element(te);
2946 IconTextOverlay text_overlay;
2947 UI_icon_text_overlay_init_from_count(&text_overlay, num_elements);
2948
2949 /* Collection colors and icons covered by restrict buttons. */
2950 if (!is_clickable || x >= xmax || is_collection) {
2951 /* Placement of icons, copied from `interface_widgets.cc`. */
2952 float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
2953 x += 2.0f * aspect;
2954 y += 2.0f * aspect;
2955 bTheme *btheme = UI_GetTheme();
2956
2957 if (is_collection) {
2959 if (collection->color_tag != COLLECTION_COLOR_NONE) {
2961 y,
2962 data.icon,
2964 alpha,
2965 0.0f,
2966 btheme->collection_color[collection->color_tag].color,
2967 btheme->tui.icon_border_intensity > 0.0f,
2968 &text_overlay);
2969 return true;
2970 }
2971 }
2972
2973 /* Reduce alpha to match icon buttons */
2974 alpha *= 0.8f;
2975
2976 /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */
2977 uchar color[4];
2978 if (UI_icon_get_theme_color(data.icon, color)) {
2980 y,
2981 data.icon,
2983 alpha,
2984 0.0f,
2985 color,
2986 btheme->tui.icon_border_intensity > 0.0f,
2987 &text_overlay);
2988 }
2989 else {
2991 x, y, data.icon, UI_INV_SCALE_FAC, alpha, 0.0f, nullptr, false, &text_overlay);
2992 }
2993 }
2994 else {
2995 uiBut *but = uiDefIconBut(
2996 block,
2998 0,
2999 data.icon,
3000 x,
3001 y,
3002 UI_UNIT_X,
3003 UI_UNIT_Y,
3004 nullptr,
3005 0.0,
3006 0.0,
3007 (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->filepath : "");
3009 }
3010
3011 return true;
3012}
3013
3014static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
3015{
3016 float text[4];
3018
3019 copy_v3_v3(icon_color, text);
3020 icon_color[3] = 0.4f;
3021 copy_v3_v3(icon_border, text);
3022 icon_border[3] = 0.2f;
3023}
3024
3025/* Draw a rounded rectangle behind icons of active elements. */
3026static void outliner_draw_active_indicator(const float minx,
3027 const float miny,
3028 const float maxx,
3029 const float maxy,
3030 const float icon_color[4],
3031 const float icon_border[4])
3032{
3033 const float ufac = UI_UNIT_X / 20.0f;
3034 const float radius = UI_UNIT_Y / 4.0f;
3035 rctf rect{};
3036 BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
3037
3039 UI_draw_roundbox_aa(&rect, true, radius, icon_color);
3040 UI_draw_roundbox_aa(&rect, false, radius, icon_border);
3041 GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */
3042}
3043
3045 TreeElement *te,
3046 int xmax,
3047 int *offsx,
3048 int ys,
3049 float alpha_fac,
3050 const eOLDrawState active,
3051 const int num_elements)
3052{
3053 TreeStoreElem *tselem = TREESTORE(te);
3054
3055 if (active != OL_DRAWSEL_NONE) {
3056 float icon_color[4], icon_border[4];
3057 outliner_icon_background_colors(icon_color, icon_border);
3058 if (active == OL_DRAWSEL_ACTIVE) {
3060 icon_border[3] = 0.3f;
3061 }
3062
3063 outliner_draw_active_indicator(float(*offsx),
3064 float(ys),
3065 float(*offsx) + UI_UNIT_X,
3066 float(ys) + UI_UNIT_Y,
3067 icon_color,
3068 icon_border);
3069 }
3070
3071 if (tselem->flag & TSE_HIGHLIGHTED_ICON) {
3072 alpha_fac += 0.5;
3073 }
3075 block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements);
3076 te->xs = *offsx;
3077 te->ys = ys;
3078 te->xend = short(*offsx) + UI_UNIT_X;
3079
3080 if (num_elements > 1) {
3081 te->flag |= TE_ICONROW_MERGED;
3082 }
3083 else {
3084 te->flag |= TE_ICONROW;
3085 }
3086
3087 (*offsx) += UI_UNIT_X;
3088}
3089
3091{
3092 TreeStoreElem *tselem = TREESTORE(te);
3093
3094 int id_index = 0;
3095 if (tselem->type == TSE_SOME_ID) {
3096 id_index = BKE_idtype_idcode_to_index(te->idcode);
3097 }
3098 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3099 /* Use the index of the grease pencil ID for the grease pencil tree nodes (which are not IDs).
3100 * All the Grease Pencil layer tree stats are stored in this index in #MergedIconRow. */
3101 id_index = INDEX_ID_GP;
3102 }
3103 else {
3104 id_index = INDEX_ID_GR;
3105 }
3106
3107 if (id_index < INDEX_ID_OB) {
3108 return id_index;
3109 }
3110 if (id_index == INDEX_ID_OB) {
3111 const Object *ob = (Object *)tselem->id;
3112 return INDEX_ID_OB + ob->type;
3113 }
3114 return id_index + OB_TYPE_MAX;
3115}
3116
3122
3124 const uiFontStyle *fstyle,
3125 const TreeViewContext &tvc,
3126 SpaceOutliner *space_outliner,
3127 ListBase *lb,
3128 int level,
3129 int xmax,
3130 int *offsx,
3131 int ys,
3132 float alpha_fac,
3133 bool in_bone_hierarchy,
3134 const bool is_grease_pencil_node_hierarchy,
3135 MergedIconRow *merged)
3136{
3138
3139 LISTBASE_FOREACH (TreeElement *, te, lb) {
3140 TreeStoreElem *tselem = TREESTORE(te);
3141 te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
3142
3143 /* object hierarchy always, further constrained on level */
3144 /* Bones are also hierarchies and get a merged count, but we only start recursing into them if
3145 * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed
3146 * collection). */
3147 const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL);
3148 /* The Grease Pencil layer tree is a hierarchy where we merge and count the total number of
3149 * layers in a node. We merge the counts for all the layers and skip counting nodes that are
3150 * layer groups (for less visual clutter in the outliner). */
3151 const bool is_grease_pencil_node = (tselem->type == TSE_GREASE_PENCIL_NODE);
3152 if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
3153 (is_grease_pencil_node_hierarchy && is_grease_pencil_node) ||
3154 (in_bone_hierarchy && is_bone))
3155 {
3156 /* active blocks get white circle */
3157 if (tselem->type == TSE_SOME_ID) {
3158 if (te->idcode == ID_OB) {
3159 active = (tvc.obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
3160 }
3161 else if (is_object_data_in_editmode(tselem->id, tvc.obact)) {
3163 }
3164 else {
3165 active = tree_element_active_state_get(tvc, te, tselem);
3166 }
3167 }
3168 else {
3169 active = tree_element_type_active_state_get(tvc, te, tselem);
3170 }
3171
3172 if (!ELEM(tselem->type,
3182 TSE_BONE,
3183 TSE_EBONE,
3189 {
3190 outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1);
3191 }
3192 else if (tselem->type == TSE_GREASE_PENCIL_NODE &&
3194 {
3195 /* Grease Pencil layer groups are tree nodes, but they shouldn't be counted. We only want
3196 * to keep track of the nodes that are layers and show the total number of layers in a
3197 * node. Adding the count of groups would add a lot of clutter. */
3198 }
3199 else {
3200 const int index = tree_element_id_type_to_index(te);
3201 merged->num_elements[index]++;
3202 if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
3203 merged->tree_element[index] = te;
3204 }
3205 merged->active[index] = std::max(active, merged->active[index]);
3206 }
3207 }
3208
3209 /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */
3210 /* Also only recurse into bone hierarchies if a direct child of the collapsed element to
3211 * merge into. */
3212 const bool is_root_level_bone = is_bone && (level == 0);
3213 in_bone_hierarchy |= is_root_level_bone;
3214 /* Recurse into the grease pencil layer tree if we already are in the hierarchy or if we're at
3215 * the root level and find a grease pencil node. */
3216 const bool in_grease_pencil_node_hierarchy = is_grease_pencil_node_hierarchy ||
3217 (is_grease_pencil_node && level == 0);
3219 in_bone_hierarchy || in_grease_pencil_node_hierarchy)
3220 {
3222 fstyle,
3223 tvc,
3224 space_outliner,
3225 &te->subtree,
3226 level + 1,
3227 xmax,
3228 offsx,
3229 ys,
3230 alpha_fac,
3231 in_bone_hierarchy,
3232 in_grease_pencil_node_hierarchy,
3233 merged);
3234 }
3235 }
3236
3237 if (level == 0) {
3238 for (int i = 0; i < INDEX_ID_MAX; i++) {
3239 const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1;
3240 /* See tree_element_id_type_to_index for the index logic. */
3241 int index_base = i;
3242 if (i > INDEX_ID_OB) {
3243 index_base += OB_TYPE_MAX;
3244 }
3245 for (int j = 0; j < num_subtypes; j++) {
3246 const int index = index_base + j;
3247 if (merged->num_elements[index] != 0) {
3249 merged->tree_element[index],
3250 xmax,
3251 offsx,
3252 ys,
3253 alpha_fac,
3254 merged->active[index],
3255 merged->num_elements[index]);
3256 }
3257 }
3258 }
3259 }
3260}
3261
3262/* closed tree element */
3264{
3265 tree_iterator::all(te->subtree, [&](TreeElement *te) {
3266 /* closed items may be displayed in row of parent, don't change their coordinate! */
3267 if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
3268 te->xs = 0;
3269 te->ys = 0;
3270 te->xend = 0;
3271 }
3272 });
3273}
3274
3276 const TreeElement *te,
3277 const TreeStoreElem *tselem)
3278{
3279 if (tselem->type == TSE_SOME_ID) {
3280 switch (te->idcode) {
3281 case ID_OB: {
3282 const Object *ob = (const Object *)tselem->id;
3283 /* Lookup in view layer is logically const as it only checks a cache. */
3285 const Base *base = (te->directdata) ?
3286 (const Base *)te->directdata :
3288 const bool is_visible = (base != nullptr) &&
3291
3292 return !is_visible;
3293 }
3294 default: {
3295 if (te->parent) {
3296 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3297 }
3298 }
3299 }
3300 }
3301 switch (tselem->type) {
3302 case TSE_LAYER_COLLECTION: {
3303 const LayerCollection *layer_collection = (const LayerCollection *)te->directdata;
3304 const bool is_visible = layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER;
3305 const bool is_excluded = layer_collection->flag & LAYER_COLLECTION_EXCLUDE;
3306 return !is_visible || is_excluded;
3307 }
3311 return !node.is_visible();
3312 }
3313 default: {
3314 if (te->parent) {
3315 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3316 }
3317 }
3318 }
3319
3320 if (te->flag & TE_CHILD_NOT_IN_COLLECTION) {
3321 return true;
3322 }
3323
3324 return false;
3325}
3326
3328 const uiFontStyle *fstyle,
3329 const TreeViewContext &tvc,
3330 ARegion *region,
3331 SpaceOutliner *space_outliner,
3332 TreeElement *te,
3333 bool draw_grayed_out,
3334 int startx,
3335 int *starty,
3336 const float restrict_column_width,
3337 TreeElement **te_edit)
3338{
3339 TreeStoreElem *tselem = TREESTORE(te);
3340 float ufac = UI_UNIT_X / 20.0f;
3341 int offsx = 0;
3343 uchar text_color[4];
3344 UI_GetThemeColor4ubv(TH_TEXT, text_color);
3345 float icon_bgcolor[4], icon_border[4];
3346 outliner_icon_background_colors(icon_bgcolor, icon_border);
3347
3348 if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) {
3349 const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
3350 int xmax = region->v2d.cur.xmax;
3351
3352 if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
3353 *te_edit = te;
3354 }
3355
3356 /* Icons can be UI buts, we don't want it to overlap with restrict. */
3357 if (restrict_column_width > 0) {
3358 xmax -= restrict_column_width + UI_UNIT_X;
3359 }
3360
3362
3363 /* Colors for active/selected data. */
3364 if (tselem->type == TSE_SOME_ID) {
3365 if (te->idcode == ID_OB) {
3366 Object *ob = (Object *)tselem->id;
3368 Base *base = (te->directdata) ? (Base *)te->directdata :
3370 const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
3371
3372 if (ob == tvc.obact) {
3374 }
3375
3376 if (is_selected) {
3377 if (ob == tvc.obact) {
3378 /* Active selected object. */
3380 text_color[3] = 255;
3381 }
3382 else {
3383 /* Other selected objects. */
3385 text_color[3] = 255;
3386 }
3387 }
3388 }
3389 else if (is_object_data_in_editmode(tselem->id, tvc.obact)) {
3390 /* Objects being edited. */
3392 icon_border[3] = 0.3f;
3394 }
3395 else {
3396 if (tree_element_active_state_get(tvc, te, tselem)) {
3397 /* Active items like camera or material. */
3398 icon_bgcolor[3] = 0.2f;
3400 if (te->idcode == ID_SCE) {
3401 UI_GetThemeColor3ubv(TH_TEXT_HI, text_color);
3402 text_color[3] = 255;
3403 }
3404 }
3405 }
3406 }
3407 else {
3408 active = tree_element_type_active_state_get(tvc, te, tselem);
3409 if (active != OL_DRAWSEL_NONE) {
3410 UI_GetThemeColor3ubv(TH_TEXT_HI, text_color);
3411 text_color[3] = 255;
3412 }
3413 }
3414
3415 /* Active circle. */
3416 if (active != OL_DRAWSEL_NONE) {
3417 outliner_draw_active_indicator(float(startx) + offsx + UI_UNIT_X,
3418 float(*starty),
3419 float(startx) + offsx + 2.0f * UI_UNIT_X,
3420 float(*starty) + UI_UNIT_Y,
3421 icon_bgcolor,
3422 icon_border);
3423
3424 te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */
3425 }
3426
3427 if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
3428 /* Scene collection in view layer can't expand/collapse. */
3429 }
3430 else if (te->subtree.first || (te->flag & TE_PRETEND_HAS_CHILDREN)) {
3431 /* Open/close icon, only when sub-levels, except for scene. */
3432 int icon_x = startx;
3433
3434 /* Icons a bit higher. */
3435 if (TSELEM_OPEN(tselem, space_outliner)) {
3437 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_DOWNARROW_HLT, alpha_fac);
3438 }
3439 else {
3441 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_RIGHTARROW, alpha_fac);
3442 }
3443 }
3444 offsx += UI_UNIT_X;
3445
3446 /* Data-type icon. */
3448 tselem_draw_icon(block,
3449 xmax,
3450 float(startx) + offsx,
3451 float(*starty),
3452 tselem,
3453 te,
3454 (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
3455 true,
3456 1))
3457 {
3458 offsx += UI_UNIT_X + 4 * ufac;
3459 }
3460 else {
3461 offsx += 2 * ufac;
3462 }
3463
3466 (te_rna_struct && RNA_struct_is_ID(te_rna_struct->get_pointer_rna().type)))
3467 {
3468 const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
3469 if (lib_icon != ICON_NONE) {
3471 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, lib_icon, alpha_fac);
3472 offsx += UI_UNIT_X + 4 * ufac;
3473 }
3474
3475 if (tselem->type == TSE_LAYER_COLLECTION) {
3476 const Collection *collection = (Collection *)tselem->id;
3477 if (!BLI_listbase_is_empty(&collection->exporters)) {
3479 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, ICON_EXPORT, alpha_fac);
3480 offsx += UI_UNIT_X + 4 * ufac;
3481 }
3482 }
3483 }
3485
3486 /* Name. */
3487 if ((tselem->flag & TSE_TEXTBUT) == 0) {
3489 UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_color);
3490 text_color[3] = 255;
3491 }
3492 text_color[3] *= alpha_fac;
3493 UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_color);
3494 }
3495
3496 offsx += int(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
3497
3498 /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */
3499 if (!TSELEM_OPEN(tselem, space_outliner)) {
3500 if (te->subtree.first) {
3501 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
3502 /* Pass. */
3503 }
3504 /* this tree element always has same amount of branches, so don't draw */
3505 else if (tselem->type != TSE_R_LAYER) {
3506 int tempx = startx + offsx;
3507
3509
3510 MergedIconRow merged{};
3512 fstyle,
3513 tvc,
3514 space_outliner,
3515 &te->subtree,
3516 0,
3517 xmax,
3518 &tempx,
3519 *starty,
3520 alpha_fac,
3521 false,
3522 false,
3523 &merged);
3524
3526 }
3527 }
3528 }
3529 }
3530 /* Store coord and continue, we need coordinates for elements outside view too. */
3531 te->xs = startx;
3532 te->ys = *starty;
3533 te->xend = startx + offsx;
3534
3535 if (TSELEM_OPEN(tselem, space_outliner)) {
3536 *starty -= UI_UNIT_Y;
3537
3538 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
3539 /* Check if element needs to be drawn grayed out, but also gray out
3540 * children of a grayed out parent (pass on draw_grayed_out to children). */
3541 bool draw_children_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
3543 fstyle,
3544 tvc,
3545 region,
3546 space_outliner,
3547 ten,
3548 draw_children_grayed_out,
3549 startx + UI_UNIT_X,
3550 starty,
3551 restrict_column_width,
3552 te_edit);
3553 }
3554 }
3555 else {
3557 *starty -= UI_UNIT_Y;
3558 }
3559}
3560
3562{
3563 LISTBASE_FOREACH (TreeElement *, te, lb) {
3564 TreeStoreElem *tselem = TREESTORE(te);
3565 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3566 return true;
3567 }
3568 }
3569 return false;
3570}
3571
3573 const uint pos, const int x, const int y1, const int y2, const bool draw_dashed)
3574{
3575 /* Small vertical padding. */
3576 const short line_padding = UI_UNIT_Y / 4.0f;
3577
3578 /* >= is 1.0 for un-dashed lines. */
3579 immUniform1f("udash_factor", draw_dashed ? 0.5f : 1.0f);
3580
3582 /* Intentionally draw from top to bottom, so collapsing a child item doesn't make the dashes
3583 * appear to move. */
3584 immVertex2f(pos, x, y2 + line_padding);
3585 immVertex2f(pos, x, y1 - line_padding);
3586 immEnd();
3587}
3588
3590 SpaceOutliner *space_outliner,
3591 ListBase *lb,
3592 const TreeViewContext &tvc,
3593 int startx,
3594 const uchar col[4],
3595 bool draw_grayed_out,
3596 int *starty)
3597{
3598 bTheme *btheme = UI_GetTheme();
3599 int y = *starty;
3600
3601 /* Draw vertical lines between collections */
3602 bool draw_hierarchy_line;
3603 bool is_object_line;
3604 LISTBASE_FOREACH (TreeElement *, te, lb) {
3605 TreeStoreElem *tselem = TREESTORE(te);
3606 draw_hierarchy_line = false;
3607 is_object_line = false;
3608 *starty -= UI_UNIT_Y;
3609 short color_tag = COLLECTION_COLOR_NONE;
3610
3611 /* Only draw hierarchy lines for expanded collections and objects with children. */
3612 if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
3613 if (tselem->type == TSE_LAYER_COLLECTION) {
3614 draw_hierarchy_line = true;
3615
3617 color_tag = collection->color_tag;
3618
3619 y = *starty;
3620 }
3621 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3622 if (subtree_contains_object(&te->subtree)) {
3623 draw_hierarchy_line = true;
3624 is_object_line = true;
3625 y = *starty;
3626 }
3627 }
3628 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3631 if (node.is_group() && node.as_group().num_direct_nodes() > 0) {
3632 draw_hierarchy_line = true;
3633 y = *starty;
3634 }
3635 }
3636
3638 space_outliner,
3639 &te->subtree,
3640 tvc,
3641 startx + UI_UNIT_X,
3642 col,
3643 draw_grayed_out,
3644 starty);
3645 }
3646
3647 if (draw_hierarchy_line) {
3648 const short alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 127 : 255;
3649 uchar line_color[4];
3650 if (color_tag != COLLECTION_COLOR_NONE) {
3651 copy_v4_v4_uchar(line_color, btheme->collection_color[color_tag].color);
3652 }
3653 else {
3654 copy_v4_v4_uchar(line_color, col);
3655 }
3656
3657 line_color[3] = alpha_fac;
3658 immUniformColor4ubv(line_color);
3659 outliner_draw_hierarchy_line(pos, startx, y, *starty, is_object_line);
3660 }
3661 }
3662}
3663
3665 ListBase *lb,
3666 const TreeViewContext &tvc,
3667 int startx,
3668 int *starty)
3669{
3672 uchar col[4];
3673
3675
3676 float viewport_size[4];
3677 GPU_viewport_size_get_f(viewport_size);
3678 immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
3679 immUniform1i("colors_len", 0); /* "simple" mode */
3680 immUniform1f("dash_width", 8.0f);
3682 col[3] = 255;
3683
3684 GPU_line_width(1.0f);
3687 pos, space_outliner, lb, tvc, startx, col, false, starty);
3689
3691}
3692
3694 SpaceOutliner *space_outliner,
3695 ListBase *lb,
3696 int *starty)
3697{
3698 LISTBASE_FOREACH (TreeElement *, te, lb) {
3699 TreeStoreElem *tselem = TREESTORE(te);
3700
3701 /* Selection status. */
3702 if (TSELEM_OPEN(tselem, space_outliner)) {
3703 if (tselem->type == TSE_RNA_STRUCT) {
3707 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3708 immRectf(pos, 0, *starty + 1, int(region->v2d.cur.xmax), *starty + UI_UNIT_Y - 1);
3710 }
3711 }
3712
3713 *starty -= UI_UNIT_Y;
3714 if (TSELEM_OPEN(tselem, space_outliner)) {
3715 outliner_draw_struct_marks(region, space_outliner, &te->subtree, starty);
3716 if (tselem->type == TSE_RNA_STRUCT) {
3720 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3721
3723 immVertex2f(pos, 0, float(*starty) + UI_UNIT_Y);
3724 immVertex2f(pos, region->v2d.cur.xmax, float(*starty) + UI_UNIT_Y);
3725 immEnd();
3726
3728 }
3729 }
3730 }
3731}
3732
3734 const ARegion *region,
3735 const SpaceOutliner *space_outliner,
3736 const float col_selection[4],
3737 const float col_active[4],
3738 const float col_highlight[4],
3739 const float col_searchmatch[4],
3740 int start_x,
3741 int *io_start_y)
3742{
3743 const bool is_searching = (SEARCHING_OUTLINER(space_outliner) ||
3744 (space_outliner->outlinevis == SO_DATA_API &&
3745 space_outliner->search_string[0] != 0));
3746
3747 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
3748 const TreeStoreElem *tselem = TREESTORE(te);
3749 const int start_y = *io_start_y;
3750
3751 /* Selection status. */
3752 if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
3753 immUniformColor4fv(col_active);
3754 immRectf(pos, 0, start_y, int(region->v2d.cur.xmax), start_y + UI_UNIT_Y);
3755 }
3756 else if (tselem->flag & TSE_SELECTED) {
3757 immUniformColor4fv(col_selection);
3758 immRectf(pos, 0, start_y, int(region->v2d.cur.xmax), start_y + UI_UNIT_Y);
3759 }
3760
3761 /* Highlights. */
3762 if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
3763 const int end_x = int(region->v2d.cur.xmax);
3764
3765 if (tselem->flag & TSE_DRAG_ANY) {
3766 /* Drag and drop highlight. */
3767 float col[4];
3769
3770 if (tselem->flag & TSE_DRAG_BEFORE) {
3772 immRectf(pos,
3773 start_x,
3774 start_y + UI_UNIT_Y - U.pixelsize,
3775 end_x,
3776 start_y + UI_UNIT_Y + U.pixelsize);
3777 }
3778 else if (tselem->flag & TSE_DRAG_AFTER) {
3780 immRectf(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize);
3781 }
3782 else {
3783 immUniformColor3fvAlpha(col, col[3] * 0.5f);
3784 immRectf(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
3785 }
3786 }
3787 else {
3788 if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
3789 /* Search match highlights. We don't expand items when searching in the data-blocks,
3790 * but we still want to highlight any filter matches. */
3791 immUniformColor4fv(col_searchmatch);
3792 immRectf(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
3793 }
3794 else if (tselem->flag & TSE_HIGHLIGHTED) {
3795 /* Mouse hover highlight. */
3796 immUniformColor4fv(col_highlight);
3797 immRectf(pos, 0, start_y, end_x, start_y + UI_UNIT_Y);
3798 }
3799 }
3800 }
3801
3802 *io_start_y -= UI_UNIT_Y;
3803 });
3804}
3805
3807 SpaceOutliner *space_outliner,
3808 int startx,
3809 int *starty)
3810{
3811 const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
3812 float col_selection[4], col_active[4], col_searchmatch[4];
3813
3815 col_selection[3] = 1.0f; /* No alpha. */
3817 col_active[3] = 1.0f; /* No alpha. */
3818 UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
3819 col_searchmatch[3] = 0.5f;
3820
3826 region,
3827 space_outliner,
3828 col_selection,
3829 col_active,
3830 col_highlight,
3831 col_searchmatch,
3832 startx,
3833 starty);
3836}
3837
3838static void outliner_draw_tree(uiBlock *block,
3839 const TreeViewContext &tvc,
3840 ARegion *region,
3841 SpaceOutliner *space_outliner,
3842 const float right_column_width,
3843 const bool use_mode_column,
3844 const bool use_warning_column,
3845 TreeElement **te_edit)
3846{
3847 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
3848
3849 short columns_offset = use_mode_column ? UI_UNIT_X : 0;
3850
3851 /* Move the tree a unit left in view layer mode */
3852 if ((space_outliner->outlinevis == SO_VIEW_LAYER) &&
3853 !(space_outliner->filter & SO_FILTER_NO_COLLECTION) &&
3854 (space_outliner->filter & SO_FILTER_NO_VIEW_LAYERS))
3855 {
3856 columns_offset -= UI_UNIT_X;
3857 }
3858
3859 if (use_warning_column) {
3860 columns_offset += UI_UNIT_X;
3861 }
3862
3863 GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
3864
3865 if (space_outliner->outlinevis == SO_DATA_API) {
3866 /* struct marks */
3867 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3868 outliner_draw_struct_marks(region, space_outliner, &space_outliner->tree, &starty);
3869 }
3870
3871 /* Draw highlights before hierarchy. */
3872 int scissor[4] = {0};
3873 {
3874 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3875 int startx = 0;
3876 outliner_draw_highlights(region, space_outliner, startx, &starty);
3877
3878 /* Set scissor so tree elements or lines can't overlap restriction icons. */
3879 if (right_column_width > 0.0f) {
3880 int mask_x = BLI_rcti_size_x(&region->v2d.mask) - int(right_column_width) + 1;
3881 CLAMP_MIN(mask_x, 0);
3882
3883 GPU_scissor_get(scissor);
3884 GPU_scissor(0, 0, mask_x, region->winy);
3885 }
3886 }
3887
3888 /* Draw hierarchy lines for collections and object children. */
3889 {
3890 int starty = int(region->v2d.tot.ymax) - OL_Y_OFFSET;
3891 int startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
3892 outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, tvc, startx, &starty);
3893 }
3894
3895 /* Items themselves. */
3896 {
3897 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3898 int startx = columns_offset;
3899 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
3901 fstyle,
3902 tvc,
3903 region,
3904 space_outliner,
3905 te,
3906 (te->flag & TE_DRAGGING) != 0,
3907 startx,
3908 &starty,
3909 right_column_width,
3910 te_edit);
3911 }
3912
3913 if (right_column_width > 0.0f) {
3914 /* Reset scissor. */
3915 GPU_scissor(UNPACK4(scissor));
3916 }
3917 }
3918}
3919
3920static void outliner_back(ARegion *region)
3921{
3922 int ystart;
3923
3924 ystart = int(region->v2d.tot.ymax);
3925 ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
3926
3929
3931
3932 float col_alternating[4];
3933 UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating);
3935
3936 const float x1 = 0.0f, x2 = region->v2d.cur.xmax;
3937 float y1 = ystart, y2;
3938 int tot = int(floor(ystart - region->v2d.cur.ymin + 2 * UI_UNIT_Y)) / (2 * UI_UNIT_Y);
3939
3940 if (tot > 0) {
3941 immBegin(GPU_PRIM_TRIS, 6 * tot);
3942 while (tot--) {
3943 y1 -= 2 * UI_UNIT_Y;
3944 y2 = y1 + UI_UNIT_Y;
3945 immVertex2f(pos, x1, y1);
3946 immVertex2f(pos, x2, y1);
3947 immVertex2f(pos, x2, y2);
3948
3949 immVertex2f(pos, x1, y1);
3950 immVertex2f(pos, x2, y2);
3951 immVertex2f(pos, x1, y2);
3952 }
3953 immEnd();
3954 }
3956}
3957
3958static int outliner_data_api_buttons_start_x(int max_tree_width)
3959{
3960 return max_ii(OL_RNA_COLX, max_tree_width + OL_RNA_COL_SPACEX);
3961}
3962
3963static int outliner_width(SpaceOutliner *space_outliner,
3964 int max_tree_width,
3965 float right_column_width)
3966{
3967 if (space_outliner->outlinevis == SO_DATA_API) {
3968 return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX +
3969 10 * UI_SCALE_FAC;
3970 }
3971 return max_tree_width + right_column_width;
3972}
3973
3975 SpaceOutliner *space_outliner,
3976 int tree_width,
3977 int tree_height,
3978 float right_column_width)
3979{
3980 int sizex = outliner_width(space_outliner, tree_width, right_column_width);
3981 int sizey = tree_height;
3982
3983 /* Extend size to allow for horizontal scroll-bar and extra offset. */
3984 sizey += V2D_SCROLL_HEIGHT + OL_Y_OFFSET;
3985
3986 UI_view2d_totRect_set(&region->v2d, sizex, sizey);
3987}
3988
3990
3991/* -------------------------------------------------------------------- */
3996
3997void draw_outliner(const bContext *C, bool do_rebuild)
3998{
3999 Main *mainvar = CTX_data_main(C);
4000 ARegion *region = CTX_wm_region(C);
4001 View2D *v2d = &region->v2d;
4002 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
4003 uiBlock *block;
4004 TreeElement *te_edit = nullptr;
4005
4006 TreeViewContext tvc;
4008
4009 /* FIXME(@ideasman42): There is an order of initialization problem here between
4010 * `v2d->cur` & `v2d->tot` where this function reads from `v2d->cur` for the scroll position
4011 * but may reset the scroll position *without* drawing into the clamped position.
4012 *
4013 * The `on_scroll` argument is used for an optional second draw pass.
4014 *
4015 * See `USE_OUTLINER_DRAW_CLAMPS_SCROLL_HACK` & #128346 for a full description. */
4016
4017 if (do_rebuild) {
4018 outliner_build_tree(mainvar, tvc.scene, tvc.view_layer, space_outliner, region); /* Always. */
4019
4020 /* If global sync select is dirty, flag other outliners. */
4023 }
4024
4025 /* Sync selection state from view layer. */
4026 if (space_outliner->flag & SO_SYNC_SELECT) {
4027 if (!ELEM(space_outliner->outlinevis,
4032 {
4033 outliner_sync_selection(C, tvc, space_outliner);
4034 }
4035 }
4036 }
4037
4038 /* Force display to pixel coords. */
4040 /* Set matrix for 2D-view controls. */
4042
4043 /* Only show mode column in View Layers and Scenes view. */
4044 const bool use_mode_column = outliner_shows_mode_column(*space_outliner);
4045 const bool use_warning_column = outliner_has_element_warnings(*space_outliner);
4046
4047 /* Draw outliner stuff (background, hierarchy lines and names). */
4048 const float right_column_width = outliner_right_columns_width(space_outliner);
4049 outliner_back(region);
4050 block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
4051 outliner_draw_tree(block,
4052 tvc,
4053 region,
4054 space_outliner,
4055 right_column_width,
4056 use_mode_column,
4057 use_warning_column,
4058 &te_edit);
4059
4060 /* Compute outliner dimensions after it has been drawn. */
4061 int tree_width, tree_height;
4062 outliner_tree_dimensions(space_outliner, &tree_width, &tree_height);
4063
4064 /* Default to no emboss for outliner UI. */
4066
4067 if (space_outliner->outlinevis == SO_DATA_API) {
4068 int buttons_start_x = outliner_data_api_buttons_start_x(tree_width);
4069 /* draw rna buttons */
4070 outliner_draw_separator(region, buttons_start_x);
4071 outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
4072
4074 outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x);
4076 }
4077 else if (ELEM(space_outliner->outlinevis, SO_ID_ORPHANS, SO_LIBRARIES)) {
4078 outliner_draw_userbuts(block, region, space_outliner);
4079 }
4080 else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
4081 const int x = region->v2d.cur.xmax - right_column_width;
4082 outliner_draw_separator(region, x);
4086 outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x);
4088 }
4089 else if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_HIERARCHIES) {
4091 mainvar, block, region, space_outliner, &space_outliner->tree, x);
4092 }
4093 }
4094 else if (right_column_width > 0.0f) {
4095 /* draw restriction columns */
4096 RestrictPropertiesActive props_active;
4097 memset(&props_active, 1, sizeof(RestrictPropertiesActive));
4099 tvc.scene,
4100 tvc.view_layer,
4101 region,
4102 space_outliner,
4103 &space_outliner->tree,
4104 props_active);
4105 }
4106
4107 /* Draw mode icons */
4108 if (use_mode_column) {
4109 outliner_draw_mode_column(block, tvc, space_outliner);
4110 }
4111
4112 /* Draw warning icons */
4113 if (use_warning_column) {
4114 outliner_draw_warning_column(block, space_outliner, use_mode_column);
4115 }
4116
4118
4119 /* Draw edit buttons if necessary. */
4120 if (te_edit) {
4121 outliner_buttons(C, block, region, right_column_width, te_edit);
4122 }
4123
4124 UI_block_end(C, block);
4125 UI_block_draw(C, block);
4126
4127 /* Update total viewable region. */
4129 region, space_outliner, tree_width, tree_height, right_column_width);
4130}
4131
4133
4134} // namespace blender::ed::outliner
4135
4140
4142{
4143 return !((space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) &&
4145}
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)
Functions to insert, delete or modify keyframes.
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)
support for deformation groups and hooks.
void BKE_object_defgroup_unique_name(bDeformGroup *dg, Object *ob)
Definition deform.cc:741
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:229
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:353
void id_us_min(ID *id)
Definition lib_id.cc:361
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:171
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
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:537
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
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.cc:404
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE], int number_to_format) ATTR_NONNULL(1)
Definition string.cc:1292
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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 STREQ(a, b)
#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)
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:682
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1012
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:353
@ INDEX_ID_GR
Definition DNA_ID.h:1249
@ INDEX_ID_OB
Definition DNA_ID.h:1248
@ INDEX_ID_GP
Definition DNA_ID.h:1245
@ ID_TAG_EXTRAUSER
Definition DNA_ID.h:786
@ ID_TAG_MISSING
Definition DNA_ID.h:775
@ 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
@ 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
@ LAYERGROUP_COLOR_NONE
@ BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT
@ LAYER_COLLECTION_EXCLUDE
@ VIEW_LAYER_RENDER
@ LAYER_COLLECTION_VISIBLE_VIEW_LAYER
@ 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_DUPLICOLLECTION
@ OB_EMPTY_IMAGE
@ 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_CURVES
@ OB_LIGHTPROBE
#define OB_DATA_SUPPORT_EDITMODE(_type)
@ TSE_DRAG_AFTER
@ TSE_SELECTED
@ TSE_HIGHLIGHTED_ICON
@ TSE_HIGHLIGHTED
@ TSE_SEARCHMATCH
@ TSE_DRAG_BEFORE
@ TSE_DRAG_ANY
@ TSE_ACTIVE
@ TSE_TEXTBUT
@ TSE_STRIP_DUP
@ TSE_BONE_COLLECTION
@ TSE_ACTION_SLOT
@ TSE_POSE_CHANNEL
@ TSE_CONSTRAINT_BASE
@ TSE_LIBRARY_OVERRIDE_OPERATION
@ TSE_STRIP
@ TSE_MODIFIER_BASE
@ TSE_GP_LAYER
@ TSE_RNA_ARRAY_ELEM
@ TSE_GPENCIL_EFFECT
@ TSE_LINKED_NODE_TREE
@ TSE_STRIP_DATA
@ 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_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
@ SCE_OBJECT_MODE_LOCK
#define BASE_SELECTED(v3d, base)
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_GAMCROSS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_ADD
@ STRIP_TYPE_TRANSFORM
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SUB
@ STRIP_TYPE_MUL
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MULTICAM
@ STRIP_TYPE_MASK
@ STRIP_TYPE_ALPHAUNDER
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ 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_FILTER_NO_VIEW_LAYERS
@ SO_FILTER_NO_COLLECTION
@ 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 BIFIconID
Definition ED_asset.hh:29
int ED_file_extension_icon(const char *path)
Definition filelist.cc:2842
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:99
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 immRectf(uint pos, float x1, float y1, float x2, float 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:166
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:193
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
void GPU_scissor_get(int coords[4])
Definition gpu_state.cc:268
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
PropertyType
Definition RNA_types.hh:149
@ PROP_ENUM
Definition RNA_types.hh:154
@ PROP_POINTER
Definition RNA_types.hh:155
#define C
Definition RandGen.cpp:29
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
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
@ UI_CNR_ALL
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
@ UI_BUT_ICON_REVERSE
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, std::optional< blender::StringRef > tip)
std::optional< int64_t > UI_but_context_int_get(const uiBut *but, blender::StringRef name)
void UI_but_drawflag_enable(uiBut *but, int flag)
void uiDefAutoButsArrayR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const int icon, const int x, const int y, const int tot_width, const int height)
void UI_draw_roundbox_corner_set(int type)
void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_fn)
void UI_but_context_int_set(uiBlock *block, uiBut *but, blender::StringRef name, int64_t value)
uiBut * uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, std::optional< blender::StringRef > name, int icon, int x, int y, int width, int height)
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, std::optional< blender::StringRef > tip)
uiBut * uiDefIconButO(uiBlock *block, int type, blender::StringRefNull opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_but_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
void UI_block_draw(const bContext *C, uiBlock *block)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > 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, std::optional< blender::StringRef > 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)
@ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE
void UI_but_label_alpha_factor_set(uiBut *but, float alpha_factor)
void UI_but_icon_indicator_color_set(uiBut *but, const uchar color[4])
#define UI_FSTYLE_WIDGET
#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)
@ UI_BUT_DRAG_LOCK
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
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, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
#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
@ TH_TEXT_HI
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()
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:1036
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
#define NC_ID
Definition WM_types.hh:392
@ KM_CTRL
Definition WM_types.hh:276
@ KM_SHIFT
Definition WM_types.hh:275
#define ND_DATA
Definition WM_types.hh:506
#define ND_RENDER_OPTIONS
Definition WM_types.hh:432
#define NC_ANIMATION
Definition WM_types.hh:385
#define NC_SCENE
Definition WM_types.hh:375
#define ND_MODIFIER
Definition WM_types.hh:459
#define ND_POSE
Definition WM_types.hh:455
#define NA_EDITED
Definition WM_types.hh:581
#define NC_MATERIAL
Definition WM_types.hh:377
#define NC_IMAGE
Definition WM_types.hh:381
#define NC_GPENCIL
Definition WM_types.hh:396
#define NC_TEXTURE
Definition WM_types.hh:378
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
#define ND_BONE_COLLECTION
Definition WM_types.hh:471
#define NA_RENAME
Definition WM_types.hh:585
#define NC_OBJECT
Definition WM_types.hh:376
#define ND_ANIMCHAN
Definition WM_types.hh:493
#define NC_SPACE
Definition WM_types.hh:389
#define NA_SELECTED
Definition WM_types.hh:586
#define ND_SPACE_OUTLINER
Definition WM_types.hh:524
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)
#define U
BMesh const char void * data
constexpr bool is_empty() const
const LayerGroup & as_group() const
const LayerGroup * parent_group() const
virtual StringRefNull get_warning() const
#define offsetof(t, d)
bool ED_id_rename(Main &bmain, ID &id, blender::StringRefNull name)
uint pos
uint col
#define active
#define select(A, B, C)
#define floor
#define ID_FAKE_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_IS_LINKED(_id)
#define MAX_ID_NAME
#define ID_NLA
#define ID_IS_EDITABLE(_id)
#define INDEX_ID_MAX
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
format
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
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 *)
eOLDrawState tree_element_type_active_state_get(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
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 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 outliner_draw_tree(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 void namebutton_fn(bContext *C, void *tsep, char *oldname)
void tree_element_activate(bContext *C, const TreeViewContext &tvc, TreeElement *te, eOLSetState set, bool handle_all_types)
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner, ListBase *lb, const TreeViewContext &tvc, int startx, int *starty)
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
static bool outliner_collection_is_isolated(Scene *scene, const LayerCollection *layer_collection_cmp, const Collection *collection_cmp, const bool value_cmp, PropertyRNA *layer_or_collection_prop, LayerCollection *layer_collection, Collection *collection)
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)
void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *space_outliner, ARegion *region)
static bool outliner_but_identity_cmp_context_id_fn(const uiBut *a, const uiBut *b)
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)
void outliner_item_mode_toggle(bContext *C, const TreeViewContext &tvc, TreeElement *te, bool do_extend)
static void outliner_draw_tree_element(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 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)
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_mode_column(uiBlock *block, TreeViewContext &tvc, SpaceOutliner *space_outliner)
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)
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_draw_warning_tree_element(uiBlock *block, const SpaceOutliner *space_outliner, const StringRef warning_msg, const bool use_mode_column, const int te_ys)
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)
void outliner_sync_selection(const bContext *C, const TreeViewContext &tvc, SpaceOutliner *space_outliner)
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_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 bool element_should_draw_faded(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
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)
eOLDrawState tree_element_active_state_get(const TreeViewContext &tvc, const TreeElement *te, const TreeStoreElem *tselem)
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 void outliner_draw_mode_column_toggle(uiBlock *block, const TreeViewContext &tvc, TreeElement *te, const bool lock_object_modes)
void draw_outliner(const bContext *C, bool do_rebuild)
static void restrictbutton_id_user_toggle(bContext *, void *poin, void *)
static void outliner_draw_iconrow(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 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)
bool ED_outliner_support_searching(const SpaceOutliner *space_outliner)
#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)
bool RNA_property_boolean_get_default(PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
PointerRNA RNA_id_pointer_create(ID *id)
short flag
struct Object * object
char name[64]
ListBase childbase
struct Collection * collection
Collection_Runtime runtime
short ob_type
char name[64]
unsigned int flag
Definition DNA_ID.h:338
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
int us
Definition DNA_ID.h:425
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
ListBase layer_collections
struct Collection * collection
char filepath[1024]
Definition DNA_ID.h:507
short type
void * first
ListBase objects
Definition BKE_main.hh:247
short transflag
struct Collection * instance_collection
ListBase modifiers
struct PartDeflect * pd
char empty_drawtype
StructRNA * type
Definition RNA_types.hh:52
struct Collection * master_collection
struct ToolSettings * toolsettings
char search_string[64]
short lib_override_view_mode
struct BLI_mempool * treestore
unsigned char color[4]
float icon_border_intensity
ListBase layer_collections
char name[64]
ListBase * edbo
bNodeTreeTypeHandle * typeinfo
struct Bone * bone
ThemeUI tui
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 xmax
float ymax
float ymin
wmEventModifierFlag modifier
Definition WM_types.hh:771
struct wmEvent * eventstate
i
Definition text_draw.cc:230
uint len
static DynamicLibrary lib
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
uint8_t flag
Definition wm_window.cc:139