Blender V5.0
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_utf8.h"
27#include "BLI_string_utils.hh"
28#include "BLI_utildefines.h"
29
30#include "BLT_translation.hh"
31
32#include "BKE_action.hh"
33#include "BKE_armature.hh"
34#include "BKE_context.hh"
35#include "BKE_curve.hh"
36#include "BKE_deform.hh"
37#include "BKE_gpencil_legacy.h"
38#include "BKE_grease_pencil.hh"
39#include "BKE_idtype.hh"
40#include "BKE_layer.hh"
41#include "BKE_lib_id.hh"
42#include "BKE_lib_override.hh"
43#include "BKE_library.hh"
44#include "BKE_main.hh"
45#include "BKE_main_namemap.hh"
46#include "BKE_modifier.hh"
47#include "BKE_node.hh"
48#include "BKE_object.hh"
49#include "BKE_particle.h"
50#include "BKE_report.hh"
51#include "BKE_scene.hh"
52
53#include "ANIM_armature.hh"
55#include "ANIM_keyframing.hh"
56
57#include "DEG_depsgraph.hh"
59
60#include "ED_armature.hh"
61#include "ED_fileselect.hh"
62#include "ED_id_management.hh"
63#include "ED_outliner.hh"
64#include "ED_screen.hh"
65#include "ED_undo.hh"
66
67#include "WM_api.hh"
68#include "WM_message.hh"
69#include "WM_types.hh"
70
71#include "GPU_immediate.hh"
72#include "GPU_state.hh"
73
74#include "UI_interface.hh"
75#include "UI_interface_icons.hh"
76#include "UI_resources.hh"
77#include "UI_view2d.hh"
78
79#include "RNA_access.hh"
80
81#include "outliner_intern.hh"
82#include "tree/tree_element.hh"
88#include "tree/tree_iterator.hh"
89
90namespace blender::ed::outliner {
91
92/* -------------------------------------------------------------------- */
95
96static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
97 ListBase *lb,
98 int *width,
99 int *height)
100{
101 LISTBASE_FOREACH (TreeElement *, te, lb) {
102 *width = std::max(*width, int(te->xend));
103 if (height != nullptr) {
104 *height += UI_UNIT_Y;
105 }
106
107 TreeStoreElem *tselem = TREESTORE(te);
108 if (TSELEM_OPEN(tselem, space_outliner)) {
109 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
110 }
111 else {
112 outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
113 }
114 }
115}
116
117void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *r_height)
118{
119 *r_width = 0;
120 *r_height = 0;
121 outliner_tree_dimensions_impl(space_outliner, &space_outliner->tree, r_width, r_height);
122}
123
127static bool is_object_data_in_editmode(const ID *id, const Object *obact)
128{
129 if (id == nullptr) {
130 return false;
131 }
132
133 const short id_type = GS(id->name);
134
135 return ((obact && (obact->mode & OB_MODE_EDIT)) && (id && OB_DATA_SUPPORT_EDITMODE(id_type)) &&
136 (GS(((ID *)obact->data)->name) == id_type) && BKE_object_data_is_in_editmode(obact, id));
137}
138
140
141/* -------------------------------------------------------------------- */
144
146 EditBone *ebone_parent,
147 int flag,
148 bool set_flag)
149{
150 LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
151 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
152 if (set_flag) {
153 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
154 ebone->flag |= flag;
155 }
156 else {
157 ebone->flag &= ~flag;
158 }
159 }
160 }
161}
162
163static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
164{
165 LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
166 if (set_flag) {
167 bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
168 bone->flag |= flag;
169 }
170 else {
171 bone->flag &= ~flag;
172 }
173 restrictbutton_recursive_bone(bone, flag, set_flag);
174 }
175}
176
177static void restrictbutton_r_lay_fn(bContext *C, void *poin, void * /*poin2*/)
178{
180}
181
182static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *poin2)
183{
184 const Object *ob = (Object *)poin;
185 bPoseChannel *pchan = (bPoseChannel *)poin2;
186 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
188 *ob->pose, *pchan, [&](bPoseChannel &descendent) {
189 if (pchan->drawflag & PCHAN_DRAW_HIDDEN) {
190 descendent.drawflag |= PCHAN_DRAW_HIDDEN;
191 }
192 else {
193 descendent.drawflag &= ~PCHAN_DRAW_HIDDEN;
194 }
195 });
196 }
197}
198
199static void restrictbutton_bone_select_fn(bContext *C, void *poin, void *poin2)
200{
201 bArmature *arm = static_cast<bArmature *>(poin);
202 Bone *bone = static_cast<Bone *>(poin2);
203
204 if (bone->flag & BONE_UNSELECTABLE) {
206 }
207
208 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
210 }
211
214}
215
216static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
217{
218 bArmature *arm = (bArmature *)poin;
219 EditBone *ebone = (EditBone *)poin2;
220
221 if (ebone->flag & BONE_UNSELECTABLE) {
223 }
224
225 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
227 arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
228 }
229
231}
232
233static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
234{
235 bArmature *arm = (bArmature *)poin;
236 EditBone *ebone = (EditBone *)poin2;
237 if (ebone->flag & BONE_HIDDEN_A) {
239 }
240
241 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
243 }
244
246}
247
248static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void * /*poin2*/)
249{
250 ID *id = (ID *)poin;
251
254}
255
256static void restrictbutton_id_user_toggle(bContext * /*C*/, void *poin, void * /*poin2*/)
257{
258 ID *id = (ID *)poin;
259
260 BLI_assert(id != nullptr);
261
262 if (id->flag & ID_FLAG_FAKEUSER) {
263 id_us_plus(id);
264 }
265 else {
266 id_us_min(id);
267 }
268}
269
271 Base *base,
272 Object *ob,
273 const char *propname)
274{
275 Main *bmain = CTX_data_main(C);
276 wmWindow *win = CTX_wm_window(C);
277 Scene *scene = CTX_data_scene(C);
278 ViewLayer *view_layer = CTX_data_view_layer(C);
279
280 bool extend = (win->eventstate->modifier & KM_SHIFT);
281
282 if (!extend) {
283 return;
284 }
285
286 /* Create PointerRNA and PropertyRNA for either Object or Base. */
287 ID *id = ob ? &ob->id : &scene->id;
288 StructRNA *struct_rna = ob ? &RNA_Object : &RNA_ObjectBase;
289 void *data = ob ? (void *)ob : (void *)base;
290
292 PropertyRNA *base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname);
293 const bool value = RNA_property_boolean_get(&ptr, base_or_object_prop);
294
295 Object *ob_parent = ob ? ob : base->object;
296
297 for (Object *ob_iter = static_cast<Object *>(bmain->objects.first); ob_iter;
298 ob_iter = static_cast<Object *>(ob_iter->id.next))
299 {
300 if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
301 if (ob) {
302 ptr = RNA_id_pointer_create(&ob_iter->id);
304 }
305 else {
306 BKE_view_layer_synced_ensure(scene, view_layer);
307 Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
308 /* Child can be in a collection excluded from view-layer. */
309 if (base_iter == nullptr) {
310 continue;
311 }
312 ptr = RNA_pointer_create_discrete(&scene->id, &RNA_ObjectBase, base_iter);
313 }
314 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
316 C, scene, &ptr, base_or_object_prop, -1, BKE_scene_frame_get(scene), true);
317 }
318 }
319
320 /* We don't call RNA_property_update() due to performance, so we batch update them. */
321 if (ob) {
324 }
325 else {
328 }
329}
330
334static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
335{
336 Object *ob = static_cast<Object *>(poin);
337 const char *propname = static_cast<const char *>(poin2);
338 outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
339}
340
344static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
345{
346 Base *base = static_cast<Base *>(poin);
347 const char *propname = static_cast<const char *>(poin2);
348 outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
349}
350
353 LayerCollection *layer_collection,
354 Collection *collection,
356{
357 if (collection) {
358 *ptr = RNA_id_pointer_create(&collection->id);
359 }
360 else {
361 *ptr = RNA_pointer_create_discrete(&scene->id, &RNA_LayerCollection, layer_collection);
362 }
363}
364
367 Scene *scene, ViewLayer *view_layer, Collection *collection, Object *ob, PointerRNA *ptr)
368{
369 if (collection) {
371 }
372 else {
373 BKE_view_layer_synced_ensure(scene, view_layer);
374 Base *base = BKE_view_layer_base_find(view_layer, ob);
375 *ptr = RNA_pointer_create_discrete(&scene->id, &RNA_ObjectBase, base);
376 }
377}
378
379/* NOTE: Collection is only valid when we want to change the collection data, otherwise we get it
380 * from layer collection. Layer collection is valid whenever we are looking at a view layer. */
382 ViewLayer *view_layer,
383 LayerCollection *layer_collection,
384 Collection *collection,
385 PropertyRNA *layer_or_collection_prop,
386 PropertyRNA *base_or_object_prop,
387 const bool value)
388{
389 if (!layer_collection) {
390 return;
391 }
392
394 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
395 if (layer_or_collection_prop && !RNA_property_editable(&ptr, layer_or_collection_prop)) {
396 return;
397 }
398
399 RNA_property_boolean_set(&ptr, layer_or_collection_prop, value);
400
401 /* Set the same flag for the nested objects as well. */
402 if (base_or_object_prop && !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) {
403 /* NOTE: We can't use BKE_collection_object_cache_get()
404 * otherwise we would not take collection exclusion into account. */
405 LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
406
407 outliner_base_or_object_pointer_create(scene, view_layer, collection, cob->ob, &ptr);
408 if (!RNA_property_editable(&ptr, base_or_object_prop)) {
409 continue;
410 }
411
412 RNA_property_boolean_set(&ptr, base_or_object_prop, value);
413
414 if (collection) {
416 }
417 }
418 }
419
420 /* Keep going recursively. */
421 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
422 LISTBASE_FOREACH (Link *, link, lb) {
423 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
424 Collection *collection_iter = layer_collection ?
425 (collection ? layer_collection_iter->collection : nullptr) :
426 ((CollectionChild *)link)->collection;
428 view_layer,
429 layer_collection_iter,
430 collection_iter,
431 layer_or_collection_prop,
432 base_or_object_prop,
433 value);
434 }
435
436 if (collection) {
438 }
439}
440
452 const LayerCollection *layer_collection_cmp,
453 const Collection *collection_cmp,
454 const bool value_cmp,
455 PropertyRNA *layer_or_collection_prop,
456 LayerCollection *layer_collection,
457 Collection *collection)
458{
460 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
461 const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
462 Collection *collection_ensure = collection ? collection : layer_collection->collection;
463 const Collection *collection_ensure_cmp = collection_cmp ? collection_cmp :
464 layer_collection_cmp->collection;
465
466 /* Exclude linked collections, otherwise toggling property won't reset the visibility for
467 * editable collections, see: #130579. */
468 if (layer_or_collection_prop && !RNA_property_editable(&ptr, layer_or_collection_prop)) {
469 return true;
470 }
471
472 if (collection_ensure->flag & COLLECTION_IS_MASTER) {
473 }
474 else if (collection_ensure == collection_ensure_cmp) {
475 }
476 else if (BKE_collection_has_collection(collection_ensure, (Collection *)collection_ensure_cmp) ||
477 BKE_collection_has_collection((Collection *)collection_ensure_cmp, collection_ensure))
478 {
479 /* This collection is either a parent or a child of the collection.
480 * We expect it to be set "visible" already. */
481 if (value != value_cmp) {
482 return false;
483 }
484 }
485 else {
486 /* This collection is neither a parent nor a child of the collection.
487 * We expect it to be "invisible". */
488 if (value == value_cmp) {
489 return false;
490 }
491 }
492
493 /* Keep going recursively. */
494 ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
495 LISTBASE_FOREACH (Link *, link, lb) {
496 LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
497 Collection *collection_iter = layer_collection ?
498 (collection ? layer_collection_iter->collection : nullptr) :
499 ((CollectionChild *)link)->collection;
500 if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
501 continue;
502 }
504 layer_collection_cmp,
505 collection_cmp,
506 value_cmp,
507 layer_or_collection_prop,
508 layer_collection_iter,
509 collection_iter))
510 {
511 return false;
512 }
513 }
514
515 return true;
516}
517
519 ViewLayer *view_layer,
520 LayerCollection *layer_collection,
521 Collection *collection,
522 PropertyRNA *layer_or_collection_prop,
523 const char *propname,
524 const bool value)
525{
527 const bool is_hide = strstr(propname, "hide_") || STREQ(propname, "exclude");
528
529 LayerCollection *top_layer_collection = layer_collection ?
530 static_cast<LayerCollection *>(
531 view_layer->layer_collections.first) :
532 nullptr;
533 Collection *top_collection = collection ? scene->master_collection : nullptr;
534
535 bool was_isolated = (value == is_hide);
536 was_isolated &= outliner_collection_is_isolated(scene,
537 layer_collection,
538 collection,
539 !is_hide,
540 layer_or_collection_prop,
541 top_layer_collection,
542 top_collection);
543
544 if (was_isolated) {
545 const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
546 /* Make every collection go back to its default "visibility" state. */
548 view_layer,
549 top_layer_collection,
550 top_collection,
551 layer_or_collection_prop,
552 nullptr,
553 default_value);
554 return;
555 }
556
557 /* Make every collection "invisible". */
559 view_layer,
560 top_layer_collection,
561 top_collection,
562 layer_or_collection_prop,
563 nullptr,
564 is_hide);
565
566 /* Make this collection and its children collections the only "visible". */
568 view_layer,
569 layer_collection,
570 collection,
571 layer_or_collection_prop,
572 nullptr,
573 !is_hide);
574
575 /* Make this collection direct parents also "visible". */
576 if (layer_collection) {
577 LayerCollection *lc_parent = layer_collection;
578 LISTBASE_FOREACH (LayerCollection *, lc_iter, &top_layer_collection->layer_collections) {
579 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
580 lc_parent = lc_iter;
581 break;
582 }
583 }
584
585 while (lc_parent != layer_collection) {
587 scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
588 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
589
590 LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
591 if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
592 lc_parent = lc_iter;
593 break;
594 }
595 }
596 }
597 }
598 else {
599 CollectionParent *parent;
600 Collection *child = collection;
601 while ((parent = static_cast<CollectionParent *>(child->runtime->parents.first))) {
602 if (parent->collection->flag & COLLECTION_IS_MASTER) {
603 break;
604 }
606 RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
607 child = parent->collection;
608 }
609 }
610}
611
613 LayerCollection *layer_collection,
614 Collection *collection,
615 const char *propname)
616{
617 Main *bmain = CTX_data_main(C);
618 wmWindow *win = CTX_wm_window(C);
619 Scene *scene = CTX_data_scene(C);
620 ViewLayer *view_layer = CTX_data_view_layer(C);
621
622 bool do_isolate = (win->eventstate->modifier & KM_CTRL);
623 bool extend = (win->eventstate->modifier & KM_SHIFT);
624
625 if (!ELEM(true, do_isolate, extend)) {
626 return;
627 }
628
629 /* Create PointerRNA and PropertyRNA for either Collection or LayerCollection. */
630 ID *id = collection ? &collection->id : &scene->id;
631 StructRNA *struct_rna = collection ? &RNA_Collection : &RNA_LayerCollection;
632 void *data = collection ? (void *)collection : (void *)layer_collection;
633
635 outliner_layer_or_collection_pointer_create(scene, layer_collection, collection, &ptr);
636 PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
637 const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
638
639 PropertyRNA *base_or_object_prop = nullptr;
640 if (layer_collection != nullptr) {
641 /* If we are toggling Layer collections we still want to change the properties of the base
642 * or the objects. If we have a matching property, toggle it as well, it can be nullptr. */
643 struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
644 base_or_object_prop = RNA_struct_type_find_property(struct_rna, propname);
645 }
646
647 if (extend) {
649 view_layer,
650 layer_collection,
651 collection,
652 layer_or_collection_prop,
653 base_or_object_prop,
654 value);
655 }
656 else {
658 view_layer,
659 layer_collection,
660 collection,
661 layer_or_collection_prop,
662 propname,
663 value);
664 }
665
666 /* We don't call RNA_property_update() due to performance, so we batch update them. */
669}
670
676 void *poin,
677 void *poin2)
678{
679 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
680 const char *propname = static_cast<const char *>(poin2);
681 outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
682}
683
688static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
689{
690 LayerCollection *layer_collection = static_cast<LayerCollection *>(poin);
691 const char *propname = static_cast<const char *>(poin2);
693 C, layer_collection, layer_collection->collection, propname);
694}
695
700static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
701{
702 Collection *collection = static_cast<Collection *>(poin);
703 const char *propname = static_cast<const char *>(poin2);
704 outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
705}
706
707static void namebutton_fn(bContext *C, void *tsep, char *oldname)
708{
709 Main *bmain = CTX_data_main(C);
710 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
712 BLI_mempool *ts = space_outliner->treestore;
713 TreeStoreElem *tselem = static_cast<TreeStoreElem *>(tsep);
714
715 const char *undo_str = nullptr;
716
717 /* Unfortunately at this point, the name of the ID has already been set to its new value. Revert
718 * it to its old name, to be able to use the generic 'rename' function for IDs.
719 *
720 * NOTE: While utterly inelegant, performances are not really a concern here, so this is an
721 * acceptable solution for now. */
722 auto id_rename_helper = [bmain, tselem, oldname]() -> bool {
723 std::string new_name = tselem->id->name + 2;
724 BLI_strncpy_utf8(tselem->id->name + 2, oldname, sizeof(tselem->id->name) - 2);
725 return ED_id_rename(*bmain, *tselem->id, new_name);
726 };
727
728 if (ts && tselem) {
729 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
730
731 if (ELEM(tselem->type, TSE_SOME_ID, TSE_LINKED_NODE_TREE)) {
732 if (id_rename_helper()) {
733 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Data-Block");
734 }
735
736 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
737
738 switch (GS(tselem->id->name)) {
739 case ID_MA:
741 break;
742 case ID_TE:
744 break;
745 case ID_IM:
747 break;
748 case ID_SCE:
750 break;
751 default:
752 break;
753 }
755
756 /* Check the library target exists */
757 if (te->idcode == ID_LI) {
758 Library *lib = (Library *)tselem->id;
759 char expanded[FILE_MAX];
760
761 BKE_library_filepath_set(bmain, lib, lib->filepath);
762
763 STRNCPY(expanded, lib->filepath);
764 BLI_path_abs(expanded, BKE_main_blendfile_path(bmain));
765 if (!BLI_exists(expanded)) {
767 RPT_ERROR,
768 "Library path '%s' does not exist, correct this before saving",
769 expanded);
770 }
771 else if (lib->id.tag & ID_TAG_MISSING) {
773 RPT_INFO,
774 "Library path '%s' is now valid, please reload the library",
775 expanded);
776 lib->id.tag &= ~ID_TAG_MISSING;
777 }
778 }
779
781 }
782 else {
783 switch (tselem->type) {
784 case TSE_DEFGROUP: {
785 Object *ob = (Object *)tselem->id;
786 bDeformGroup *vg = static_cast<bDeformGroup *>(te->directdata);
788 WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
790 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Vertex Group");
791 break;
792 }
793 case TSE_NLA_ACTION: {
794 /* The #tselem->id is a #bAction. */
795 if (id_rename_helper()) {
796 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Data-Block");
797 }
798 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
800 break;
801 }
802 case TSE_NLA_TRACK: {
804 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename NLA Track");
805 break;
806 }
807 case TSE_MODIFIER: {
810 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Modifier");
811
812 break;
813 }
814 case TSE_EBONE: {
815 bArmature *arm = (bArmature *)tselem->id;
816 if (arm->edbo) {
817 EditBone *ebone = static_cast<EditBone *>(te->directdata);
818 char newname[sizeof(ebone->name)];
819
820 /* restore bone name */
821 STRNCPY_UTF8(newname, ebone->name);
822 STRNCPY_UTF8(ebone->name, oldname);
823 ED_armature_bone_rename(bmain, arm, oldname, newname);
824 WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
827 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Edit Bone");
828 }
829 break;
830 }
831
832 case TSE_BONE: {
833 TreeViewContext tvc;
835
836 bArmature *arm = (bArmature *)tselem->id;
837 Bone *bone = static_cast<Bone *>(te->directdata);
838 char newname[sizeof(bone->name)];
839
840 /* always make current object active */
842
843 /* restore bone name */
844 STRNCPY_UTF8(newname, bone->name);
845 STRNCPY_UTF8(bone->name, oldname);
846 ED_armature_bone_rename(bmain, arm, oldname, newname);
847 WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
850 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Bone");
851 break;
852 }
853 case TSE_POSE_CHANNEL: {
854 TreeViewContext tvc;
856
857 Object *ob = (Object *)tselem->id;
858 bArmature *arm = (bArmature *)ob->data;
859 bPoseChannel *pchan = static_cast<bPoseChannel *>(te->directdata);
860 char newname[sizeof(pchan->name)];
861
862 /* always make current pose-bone active */
864
866
867 /* restore bone name */
868 STRNCPY_UTF8(newname, pchan->name);
869 STRNCPY_UTF8(pchan->name, oldname);
870 ED_armature_bone_rename(bmain, static_cast<bArmature *>(ob->data), oldname, newname);
871 WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
875 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Pose Bone");
876 break;
877 }
878 case TSE_GP_LAYER: {
879 bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
880 bGPDlayer *gpl = static_cast<bGPDlayer *>(te->directdata);
881
882 /* always make layer active */
884
885 /* XXX: name needs translation stuff. */
887 &gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
888
889 WM_msg_publish_rna_prop(mbus, &gpd->id, gpl, AnnotationLayer, info);
893 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Annotation Layer");
894 break;
895 }
897 GreasePencil &grease_pencil = *(GreasePencil *)tselem->id;
900
901 /* The node already has the new name set. To properly rename the node, we need to first
902 * store the new name, restore the old name in the node, and then call the rename
903 * function. */
904 std::string new_name(node.name());
905 node.set_name(oldname);
906 grease_pencil.rename_node(*bmain, node, new_name);
909 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Grease Pencil Drawing");
910 break;
911 }
912 case TSE_R_LAYER: {
913 Scene *scene = (Scene *)tselem->id;
914 ViewLayer *view_layer = static_cast<ViewLayer *>(te->directdata);
915
916 /* Restore old name. */
917 char newname[sizeof(view_layer->name)];
918 STRNCPY_UTF8(newname, view_layer->name);
919 STRNCPY_UTF8(view_layer->name, oldname);
920
921 /* Rename, preserving animation and compositing data. */
922 BKE_view_layer_rename(bmain, scene, view_layer, newname);
923 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
926 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename View Layer");
927 break;
928 }
930 /* The #tselem->id is a #Collection, not a #LayerCollection */
931 if (id_rename_helper()) {
932 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Data-Block");
933 }
934 WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
937 break;
938 }
939
940 case TSE_BONE_COLLECTION: {
941 bArmature *arm = (bArmature *)tselem->id;
942 BoneCollection *bcoll = static_cast<BoneCollection *>(te->directdata);
943
944 ANIM_armature_bonecoll_name_set(arm, bcoll, bcoll->name);
945 WM_msg_publish_rna_prop(mbus, &arm->id, bcoll, BoneCollection, name);
948 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Bone Collection");
949 break;
950 }
951
952 case TSE_ACTION_SLOT: {
954 undo_str = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Action Slot");
955 break;
956 }
957 }
958 }
959 tselem->flag &= ~TSE_TEXTBUT;
960 }
961
962 if (undo_str) {
963 ED_undo_push(C, undo_str);
964 }
965}
966
979
980/* We don't care about the value of the property
981 * but whether the property should be active or grayed out. */
999
1001 PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
1002{
1003 if (props_active->collection_hide_render) {
1005 collection_ptr, props->collection_hide_render);
1006 if (!props_active->collection_hide_render) {
1007 props_active->layer_collection_holdout = false;
1008 props_active->layer_collection_indirect_only = false;
1009 props_active->object_hide_render = false;
1010 props_active->modifier_show_render = false;
1011 props_active->constraint_enable = false;
1012 }
1013 }
1014
1015 if (props_active->collection_hide_viewport) {
1017 collection_ptr, props->collection_hide_viewport);
1018 if (!props_active->collection_hide_viewport) {
1019 props_active->collection_hide_select = false;
1020 props_active->object_hide_select = false;
1021 props_active->layer_collection_hide_viewport = false;
1022 props_active->object_hide_viewport = false;
1023 props_active->base_hide_viewport = false;
1024 props_active->modifier_show_viewport = false;
1025 props_active->constraint_enable = false;
1026 }
1027 }
1028
1029 if (props_active->collection_hide_select) {
1031 collection_ptr, props->collection_hide_select);
1032 if (!props_active->collection_hide_select) {
1033 props_active->object_hide_select = false;
1034 }
1035 }
1036}
1037
1039 PointerRNA *layer_collection_ptr,
1040 PointerRNA *collection_ptr,
1041 RestrictProperties *props,
1042 RestrictPropertiesActive *props_active)
1043{
1044 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1045
1046 if (props_active->layer_collection_holdout) {
1048 layer_collection_ptr, props->layer_collection_holdout);
1049 }
1050
1052 layer_collection_ptr, props->layer_collection_indirect_only);
1053
1054 if (props_active->layer_collection_hide_viewport) {
1056 layer_collection_ptr, props->layer_collection_hide_viewport);
1057
1058 if (!props_active->layer_collection_hide_viewport) {
1059 props_active->base_hide_viewport = false;
1060 props_active->collection_hide_select = false;
1061 props_active->object_hide_select = false;
1062 }
1063 }
1064
1065 if (props_active->layer_collection_exclude) {
1067 layer_collection_ptr, props->layer_collection_exclude);
1068
1069 if (!props_active->layer_collection_exclude) {
1070 props_active->collection_hide_viewport = false;
1071 props_active->collection_hide_select = false;
1072 props_active->collection_hide_render = false;
1073 props_active->layer_collection_hide_viewport = false;
1074 props_active->layer_collection_holdout = false;
1075 props_active->layer_collection_indirect_only = false;
1076 }
1077 }
1078}
1079
1081 TreeElement *te,
1082 PointerRNA *collection_ptr,
1083 PointerRNA *layer_collection_ptr,
1084 RestrictProperties *props,
1085 RestrictPropertiesActive *props_active)
1086{
1087 TreeStoreElem *tselem = TREESTORE(te);
1088 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1089 static_cast<LayerCollection *>(te->directdata) :
1090 nullptr;
1092
1093 if (collection->flag & COLLECTION_IS_MASTER) {
1094 return false;
1095 }
1096
1097 /* Create the PointerRNA. */
1098 *collection_ptr = RNA_id_pointer_create(&collection->id);
1099 if (layer_collection != nullptr) {
1100 *layer_collection_ptr = RNA_pointer_create_discrete(
1101 &scene->id, &RNA_LayerCollection, layer_collection);
1102 }
1103
1104 /* Update the restriction column values for the collection children. */
1105 if (layer_collection) {
1107 layer_collection_ptr, collection_ptr, props, props_active);
1108 }
1109 else {
1110 outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active);
1111 }
1112 return true;
1113}
1114
1116 Scene *scene,
1117 ViewLayer *view_layer,
1118 ARegion *region,
1119 SpaceOutliner *space_outliner,
1120 ListBase *lb,
1121 RestrictPropertiesActive props_active_parent)
1122{
1123 /* Get RNA properties (once for speed). */
1124 static RestrictProperties props = {false};
1125 if (!props.initialized) {
1126 props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport");
1127 props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
1128 props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
1129 props.base_hide_viewport = RNA_struct_type_find_property(&RNA_ObjectBase, "hide_viewport");
1131 "hide_viewport");
1132 props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
1133 props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
1134 props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection,
1135 "exclude");
1136 props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection,
1137 "holdout");
1139 "indirect_only");
1141 "hide_viewport");
1142 props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
1143 props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
1144
1145 props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "enabled");
1146
1147 props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_PoseBone, "hide");
1148
1149 props.initialized = true;
1150 }
1151
1152 struct {
1153 int enable;
1154 int select;
1155 int hide;
1156 int viewport;
1157 int render;
1158 int indirect_only;
1159 int holdout;
1160 } restrict_offsets = {0};
1161 int restrict_column_offset = 0;
1162
1163 /* This will determine the order of drawing from RIGHT to LEFT. */
1164 if (space_outliner->outlinevis == SO_VIEW_LAYER) {
1165 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1166 restrict_offsets.indirect_only = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1167 }
1168 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1169 restrict_offsets.holdout = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1170 }
1171 }
1172 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1173 restrict_offsets.render = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1174 }
1175 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1176 restrict_offsets.viewport = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1177 }
1178 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1179 restrict_offsets.hide = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1180 }
1181 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1182 restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1183 }
1184 if (space_outliner->outlinevis == SO_VIEW_LAYER &&
1185 space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)
1186 {
1187 restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
1188 }
1189
1190 BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
1191 outliner_right_columns_width(space_outliner));
1192
1193 /* Create buttons. */
1194 uiBut *bt;
1195
1196 LISTBASE_FOREACH (TreeElement *, te, lb) {
1197 TreeStoreElem *tselem = TREESTORE(te);
1198 RestrictPropertiesActive props_active = props_active_parent;
1199
1200 if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
1201 if (tselem->type == TSE_R_LAYER &&
1202 ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER))
1203 {
1204 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1205 /* View layer render toggle. */
1206 ViewLayer *layer = static_cast<ViewLayer *>(te->directdata);
1207
1208 bt = uiDefIconButBitS(block,
1211 0,
1212 ICON_RESTRICT_RENDER_OFF,
1213 int(region->v2d.cur.xmax - restrict_offsets.render),
1214 te->ys,
1215 UI_UNIT_X,
1216 UI_UNIT_Y,
1217 &layer->flag,
1218 0,
1219 0,
1220 TIP_("Use view layer for rendering"));
1221 UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
1224 }
1225 }
1226 else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) &&
1227 (te->flag & TE_CHILD_NOT_IN_COLLECTION))
1228 {
1229 /* Don't show restrict columns for children that are not directly inside the collection. */
1230 }
1231 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1232 Object *ob = (Object *)tselem->id;
1234
1235 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1236 BKE_view_layer_synced_ensure(scene, view_layer);
1237 Base *base = (te->directdata) ? (Base *)te->directdata :
1238 BKE_view_layer_base_find(view_layer, ob);
1239 if (base) {
1240 PointerRNA base_ptr = RNA_pointer_create_discrete(&scene->id, &RNA_ObjectBase, base);
1241 bt = uiDefIconButR_prop(block,
1243 0,
1244 ICON_NONE,
1245 int(region->v2d.cur.xmax - restrict_offsets.hide),
1246 te->ys,
1247 UI_UNIT_X,
1248 UI_UNIT_Y,
1249 &base_ptr,
1250 props.base_hide_viewport,
1251 -1,
1252 0,
1253 0,
1254 TIP_("Temporarily hide in viewport\n"
1255 " \u2022 Shift to set children"));
1257 bt, outliner__base_set_flag_recursive_fn, base, (void *)"hide_viewport");
1259 if (!props_active.base_hide_viewport) {
1261 }
1262 }
1263 }
1264
1265 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1266 bt = uiDefIconButR_prop(block,
1268 0,
1269 ICON_NONE,
1270 int(region->v2d.cur.xmax - restrict_offsets.select),
1271 te->ys,
1272 UI_UNIT_X,
1273 UI_UNIT_Y,
1274 &ptr,
1275 props.object_hide_select,
1276 -1,
1277 0,
1278 0,
1279 TIP_("Disable selection in viewport\n"
1280 " \u2022 Shift to set children"));
1281 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_select");
1283 if (!props_active.object_hide_select) {
1285 }
1286 }
1287
1288 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1289 bt = uiDefIconButR_prop(block,
1291 0,
1292 ICON_NONE,
1293 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1294 te->ys,
1295 UI_UNIT_X,
1296 UI_UNIT_Y,
1297 &ptr,
1299 -1,
1300 0,
1301 0,
1302 TIP_("Globally disable in viewports\n"
1303 " \u2022 Shift to set children"));
1304 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (void *)"hide_viewport");
1306 if (!props_active.object_hide_viewport) {
1308 }
1309 }
1310
1311 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1312 bt = uiDefIconButR_prop(block,
1314 0,
1315 ICON_NONE,
1316 int(region->v2d.cur.xmax - restrict_offsets.render),
1317 te->ys,
1318 UI_UNIT_X,
1319 UI_UNIT_Y,
1320 &ptr,
1321 props.object_hide_render,
1322 -1,
1323 0,
1324 0,
1325 TIP_("Globally disable in renders\n"
1326 " \u2022 Shift to set children"));
1327 UI_but_func_set(bt, outliner__object_set_flag_recursive_fn, ob, (char *)"hide_render");
1329 if (!props_active.object_hide_render) {
1331 }
1332 }
1333 }
1334 else if (tselem->type == TSE_CONSTRAINT) {
1335 bConstraint *con = (bConstraint *)te->directdata;
1336
1337 PointerRNA ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Constraint, con);
1338
1339 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1340 bt = uiDefIconButR_prop(block,
1342 0,
1343 ICON_NONE,
1344 int(region->v2d.cur.xmax - restrict_offsets.hide),
1345 te->ys,
1346 UI_UNIT_X,
1347 UI_UNIT_Y,
1348 &ptr,
1349 props.constraint_enable,
1350 -1,
1351 0,
1352 0,
1353 nullptr);
1355 if (!props_active.constraint_enable) {
1357 }
1358 }
1359 }
1360 else if (tselem->type == TSE_MODIFIER) {
1361 ModifierData *md = (ModifierData *)te->directdata;
1362
1363 PointerRNA ptr = RNA_pointer_create_discrete(tselem->id, &RNA_Modifier, md);
1364
1365 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1366 bt = uiDefIconButR_prop(block,
1368 0,
1369 ICON_NONE,
1370 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1371 te->ys,
1372 UI_UNIT_X,
1373 UI_UNIT_Y,
1374 &ptr,
1376 -1,
1377 0,
1378 0,
1379 std::nullopt);
1381 if (!props_active.modifier_show_viewport) {
1383 }
1384 }
1385
1386 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1387 bt = uiDefIconButR_prop(block,
1389 0,
1390 ICON_NONE,
1391 int(region->v2d.cur.xmax - restrict_offsets.render),
1392 te->ys,
1393 UI_UNIT_X,
1394 UI_UNIT_Y,
1395 &ptr,
1397 -1,
1398 0,
1399 0,
1400 std::nullopt);
1402 if (!props_active.modifier_show_render) {
1404 }
1405 }
1406 }
1407 else if (tselem->type == TSE_POSE_CHANNEL) {
1408 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
1409 Bone *bone = pchan->bone;
1410 Object *ob = (Object *)tselem->id;
1411 bArmature *arm = static_cast<bArmature *>(ob->data);
1412
1413 PointerRNA ptr = RNA_pointer_create_discrete(&arm->id, &RNA_PoseBone, pchan);
1414
1415 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1416 bt = uiDefIconButR_prop(block,
1418 0,
1419 ICON_NONE,
1420 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1421 te->ys,
1422 UI_UNIT_X,
1423 UI_UNIT_Y,
1424 &ptr,
1425 props.bone_hide_viewport,
1426 -1,
1427 0,
1428 0,
1429 TIP_("Restrict visibility in the 3D View\n"
1430 " \u2022 Shift to set children"));
1434 }
1435
1436 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1437 bt = uiDefIconButBitI(block,
1440 0,
1441 ICON_RESTRICT_SELECT_OFF,
1442 int(region->v2d.cur.xmax - restrict_offsets.select),
1443 te->ys,
1444 UI_UNIT_X,
1445 UI_UNIT_Y,
1446 &(bone->flag),
1447 0,
1448 0,
1449 TIP_("Restrict selection in the 3D View\n"
1450 " \u2022 Shift to set children"));
1454 }
1455 }
1456 else if (tselem->type == TSE_EBONE) {
1457 bArmature *arm = (bArmature *)tselem->id;
1458 EditBone *ebone = (EditBone *)te->directdata;
1459
1460 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1461 bt = uiDefIconButBitI(block,
1464 0,
1465 ICON_RESTRICT_VIEW_OFF,
1466 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1467 te->ys,
1468 UI_UNIT_X,
1469 UI_UNIT_Y,
1470 &(ebone->flag),
1471 0,
1472 0,
1473 TIP_("Restrict visibility in the 3D View\n"
1474 " \u2022 Shift to set children"));
1478 }
1479
1480 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1481 bt = uiDefIconButBitI(block,
1484 0,
1485 ICON_RESTRICT_SELECT_OFF,
1486 int(region->v2d.cur.xmax - restrict_offsets.select),
1487 te->ys,
1488 UI_UNIT_X,
1489 UI_UNIT_Y,
1490 &(ebone->flag),
1491 0,
1492 0,
1493 TIP_("Restrict selection in the 3D View\n"
1494 " \u2022 Shift to set children"));
1498 }
1499 }
1500 else if (tselem->type == TSE_GP_LAYER) {
1501 ID *id = tselem->id;
1502 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
1503
1504 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1505 bt = uiDefIconButBitS(block,
1508 0,
1509 ICON_HIDE_OFF,
1510 int(region->v2d.cur.xmax - restrict_offsets.hide),
1511 te->ys,
1512 UI_UNIT_X,
1513 UI_UNIT_Y,
1514 &gpl->flag,
1515 0,
1516 0,
1517 TIP_("Restrict visibility in the 3D View"));
1521 }
1522
1523 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1524 bt = uiDefIconButBitS(block,
1527 0,
1528 ICON_UNLOCKED,
1529 int(region->v2d.cur.xmax - restrict_offsets.select),
1530 te->ys,
1531 UI_UNIT_X,
1532 UI_UNIT_Y,
1533 &gpl->flag,
1534 0,
1535 0,
1536 TIP_("Restrict editing of strokes and keyframes in this layer"));
1539 }
1540 }
1541 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
1545 PropertyRNA *hide_prop;
1546 if (node.is_layer()) {
1547 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_GreasePencilLayer, &node);
1548 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayer, "hide");
1549 }
1550 else if (node.is_group()) {
1551 ptr = RNA_pointer_create_discrete(tselem->id, &RNA_GreasePencilLayerGroup, &node);
1552 hide_prop = RNA_struct_type_find_property(&RNA_GreasePencilLayerGroup, "hide");
1553 }
1554
1555 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1556 bt = uiDefIconButR_prop(block,
1558 0,
1559 0,
1560 int(region->v2d.cur.xmax - restrict_offsets.hide),
1561 te->ys,
1562 UI_UNIT_X,
1563 UI_UNIT_Y,
1564 &ptr,
1565 hide_prop,
1566 -1,
1567 0,
1568 0,
1569 std::nullopt);
1571 if (node.parent_group() && !node.parent_group()->is_visible()) {
1573 }
1574 }
1575 }
1577 PointerRNA collection_ptr;
1578 PointerRNA layer_collection_ptr;
1579
1581 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active))
1582 {
1583
1584 LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
1585 static_cast<LayerCollection *>(te->directdata) :
1586 nullptr;
1588
1589 if (layer_collection != nullptr) {
1590 if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
1591 bt = uiDefIconButR_prop(block,
1593 0,
1594 ICON_NONE,
1595 int(region->v2d.cur.xmax) - restrict_offsets.enable,
1596 te->ys,
1597 UI_UNIT_X,
1598 UI_UNIT_Y,
1599 &layer_collection_ptr,
1601 -1,
1602 0,
1603 0,
1604 std::nullopt);
1605 UI_but_func_set(bt,
1607 layer_collection,
1608 (char *)"exclude");
1610 }
1611
1612 if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
1613 bt = uiDefIconButR_prop(block,
1615 0,
1616 ICON_NONE,
1617 int(region->v2d.cur.xmax - restrict_offsets.hide),
1618 te->ys,
1619 UI_UNIT_X,
1620 UI_UNIT_Y,
1621 &layer_collection_ptr,
1623 -1,
1624 0,
1625 0,
1626 TIP_("Temporarily hide in viewport\n"
1627 " \u2022 Ctrl to isolate collection\n"
1628 " \u2022 Shift to set inside collections and objects"));
1629 UI_but_func_set(bt,
1631 layer_collection,
1632 (char *)"hide_viewport");
1634 if (!props_active.layer_collection_hide_viewport) {
1636 }
1637 }
1638
1639 if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
1640 bt = uiDefIconButR_prop(block,
1642 0,
1643 ICON_NONE,
1644 int(region->v2d.cur.xmax - restrict_offsets.holdout),
1645 te->ys,
1646 UI_UNIT_X,
1647 UI_UNIT_Y,
1648 &layer_collection_ptr,
1650 -1,
1651 0,
1652 0,
1653 TIP_("Mask out objects in collection from view layer\n"
1654 " \u2022 Ctrl to isolate collection\n"
1655 " \u2022 Shift to set inside collections"));
1656 UI_but_func_set(bt,
1658 layer_collection,
1659 (char *)"holdout");
1661 if (!props_active.layer_collection_holdout) {
1663 }
1664 }
1665
1666 if (space_outliner->show_restrict_flags & SO_RESTRICT_INDIRECT_ONLY) {
1667 bt = uiDefIconButR_prop(
1668 block,
1670 0,
1671 ICON_NONE,
1672 int(region->v2d.cur.xmax - restrict_offsets.indirect_only),
1673 te->ys,
1674 UI_UNIT_X,
1675 UI_UNIT_Y,
1676 &layer_collection_ptr,
1678 -1,
1679 0,
1680 0,
1681 TIP_("Objects in collection only contribute indirectly (through shadows and "
1682 "reflections) in the view layer\n"
1683 " \u2022 Ctrl to isolate collection\n"
1684 " \u2022 Shift to set inside collections"));
1685 UI_but_func_set(bt,
1687 layer_collection,
1688 (char *)"indirect_only");
1690 if (props_active.layer_collection_holdout ||
1691 !props_active.layer_collection_indirect_only)
1692 {
1694 }
1695 }
1696 }
1697
1698 if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
1699 bt = uiDefIconButR_prop(block,
1701 0,
1702 ICON_NONE,
1703 int(region->v2d.cur.xmax - restrict_offsets.viewport),
1704 te->ys,
1705 UI_UNIT_X,
1706 UI_UNIT_Y,
1707 &collection_ptr,
1709 -1,
1710 0,
1711 0,
1712 TIP_("Globally disable in viewports\n"
1713 " \u2022 Ctrl to isolate collection\n"
1714 " \u2022 Shift to set inside collections and objects"));
1715 if (layer_collection != nullptr) {
1716 UI_but_func_set(bt,
1718 layer_collection,
1719 (char *)"hide_viewport");
1720 }
1721 else {
1722 UI_but_func_set(bt,
1724 collection,
1725 (char *)"hide_viewport");
1726 }
1728 if (!props_active.collection_hide_viewport) {
1730 }
1731 }
1732
1733 if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
1734 bt = uiDefIconButR_prop(block,
1736 0,
1737 ICON_NONE,
1738 int(region->v2d.cur.xmax - restrict_offsets.render),
1739 te->ys,
1740 UI_UNIT_X,
1741 UI_UNIT_Y,
1742 &collection_ptr,
1744 -1,
1745 0,
1746 0,
1747 TIP_("Globally disable in renders\n"
1748 " \u2022 Ctrl to isolate collection\n"
1749 " \u2022 Shift to set inside collections and objects"));
1750 if (layer_collection != nullptr) {
1751 UI_but_func_set(bt,
1753 layer_collection,
1754 (char *)"hide_render");
1755 }
1756 else {
1758 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_render");
1759 }
1761 if (!props_active.collection_hide_render) {
1763 }
1764 }
1765
1766 if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
1767 bt = uiDefIconButR_prop(block,
1769 0,
1770 ICON_NONE,
1771 int(region->v2d.cur.xmax - restrict_offsets.select),
1772 te->ys,
1773 UI_UNIT_X,
1774 UI_UNIT_Y,
1775 &collection_ptr,
1777 -1,
1778 0,
1779 0,
1780 TIP_("Disable selection in viewport\n"
1781 " \u2022 Ctrl to isolate collection\n"
1782 " \u2022 Shift to set inside collections and objects"));
1783 if (layer_collection != nullptr) {
1784 UI_but_func_set(bt,
1786 layer_collection,
1787 (char *)"hide_select");
1788 }
1789 else {
1791 bt, scenes__collection_set_flag_recursive_fn, collection, (char *)"hide_select");
1792 }
1794 if (!props_active.collection_hide_select) {
1796 }
1797 }
1798 }
1799 }
1800 }
1802 PointerRNA collection_ptr;
1803 PointerRNA layer_collection_ptr;
1805 scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active);
1806 }
1807
1808 if (TSELEM_OPEN(tselem, space_outliner)) {
1810 block, scene, view_layer, region, space_outliner, &te->subtree, props_active);
1811 }
1812 }
1813}
1814
1816 const ARegion *region,
1817 const SpaceOutliner *space_outliner)
1818{
1819 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
1820 if (!outliner_is_element_in_view(te, &region->v2d)) {
1821 return;
1822 }
1823
1824 const TreeStoreElem *tselem = TREESTORE(te);
1825 ID *id = tselem->id;
1826
1827 if (tselem->type != TSE_SOME_ID || id->tag & ID_TAG_EXTRAUSER) {
1828 return;
1829 }
1830
1831 uiBut *bt;
1832 std::optional<StringRef> tip;
1833 const int real_users = id->us - ID_FAKE_USERS(id);
1834 const bool has_fake_user = id->flag & ID_FLAG_FAKEUSER;
1835 const bool is_linked = ID_IS_LINKED(id);
1836 const bool is_object = GS(id->name) == ID_OB;
1837 char overlay[5];
1838 BLI_str_format_integer_unit(overlay, id->us);
1839
1840 if (is_object) {
1841 bt = uiDefBut(block,
1843 0,
1844 overlay,
1845 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1846 te->ys,
1847 UI_UNIT_X,
1848 UI_UNIT_Y,
1849 nullptr,
1850 0.0,
1851 0.0,
1852 TIP_("Number of users"));
1853 }
1854 else {
1855
1856 if (has_fake_user) {
1857 tip = is_linked ? TIP_("Item is protected from deletion") :
1858 TIP_("Click to remove protection from deletion");
1859 }
1860 else {
1861 if (real_users) {
1862 tip = is_linked ? TIP_("Item is not protected from deletion") :
1863 TIP_("Click to add protection from deletion");
1864 }
1865 else {
1866 tip = is_linked ?
1867 TIP_("Item has no users and will be removed") :
1868 TIP_("Item has no users and will be removed.\nClick to protect from deletion");
1869 }
1870 }
1871
1872 bt = uiDefIconButBitS(block,
1875 1,
1876 ICON_FAKE_USER_OFF,
1877 int(region->v2d.cur.xmax - OL_TOG_USER_BUTS_USERS),
1878 te->ys,
1879 UI_UNIT_X,
1880 UI_UNIT_Y,
1881 &id->flag,
1882 0,
1883 0,
1884 tip);
1885
1886 if (is_linked) {
1888 }
1889 else {
1891 /* Allow _inaccurate_ dragging over multiple toggles. */
1893 }
1894
1895 if (!real_users && !has_fake_user) {
1896 uchar overlay_color[4];
1897 UI_GetThemeColor4ubv(TH_REDALERT, overlay_color);
1898 UI_but_icon_indicator_color_set(bt, overlay_color);
1899 }
1900 UI_but_icon_indicator_set(bt, overlay);
1901 }
1902 });
1903}
1904
1906 const ARegion *region,
1907 const SpaceOutliner *space_outliner,
1908 const ListBase *lb,
1909 const int x)
1910{
1911 const float pad_x = 2.0f * UI_SCALE_FAC;
1912 const float pad_y = 0.5f * U.pixelsize;
1913 const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x);
1914 const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y);
1915
1916 LISTBASE_FOREACH (const TreeElement *, te, lb) {
1917 const TreeStoreElem *tselem = TREESTORE(te);
1918 if (TSELEM_OPEN(tselem, space_outliner)) {
1919 outliner_draw_overrides_rna_buts(block, region, space_outliner, &te->subtree, x);
1920 }
1921
1922 if (!outliner_is_element_in_view(te, &region->v2d)) {
1923 continue;
1924 }
1926 te);
1927 if (!override_elem) {
1928 continue;
1929 }
1930
1931 if (!override_elem->is_rna_path_valid) {
1932 uiBut *but = uiDefBut(block,
1934 0,
1935 override_elem->rna_path,
1936 x + pad_x,
1937 te->ys + pad_y,
1938 item_max_width,
1939 item_height,
1940 nullptr,
1941 0.0f,
1942 0.0f,
1943 "");
1945 continue;
1946 }
1947
1948 if (const TreeElementOverridesPropertyOperation *override_op_elem =
1950 {
1951 StringRefNull op_label = override_op_elem->get_override_operation_label();
1952 if (!op_label.is_empty()) {
1953 uiDefBut(block,
1955 0,
1956 op_label,
1957 x + pad_x,
1958 te->ys + pad_y,
1959 item_max_width,
1960 item_height,
1961 nullptr,
1962 0,
1963 0,
1964 "");
1965 continue;
1966 }
1967 }
1968
1969 PointerRNA *ptr = &override_elem->override_rna_ptr;
1970 PropertyRNA *prop = &override_elem->override_rna_prop;
1971 const PropertyType prop_type = RNA_property_type(prop);
1972
1973 uiBut *auto_but = uiDefAutoButR(block,
1974 ptr,
1975 prop,
1976 -1,
1977 (prop_type == PROP_ENUM) ? std::nullopt : std::optional(""),
1978 ICON_NONE,
1979 x + pad_x,
1980 te->ys + pad_y,
1981 item_max_width,
1982 item_height);
1983 /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons
1984 * need to be handled. */
1985 if (auto_but) {
1986 continue;
1987 }
1988
1989 if (!auto_but) {
1990 /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension
1991 * arrays? */
1993 block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height);
1994 }
1995 }
1996}
1997
1999{
2000 const std::optional<int64_t> session_uid_a = UI_but_context_int_get(a, "session_uid");
2001 const std::optional<int64_t> session_uid_b = UI_but_context_int_get(b, "session_uid");
2002 if (!session_uid_a || !session_uid_b) {
2003 return false;
2004 }
2005 /* Using session UID to compare is safer than using the pointer. */
2006 return session_uid_a == session_uid_b;
2007}
2008
2010 uiBlock *block,
2011 const ARegion *region,
2012 const SpaceOutliner *space_outliner,
2013 const ListBase *lb,
2014 const int x)
2015{
2016 LISTBASE_FOREACH (const TreeElement *, te, lb) {
2017 const TreeStoreElem *tselem = TREESTORE(te);
2018 if (TSELEM_OPEN(tselem, space_outliner)) {
2019 outliner_draw_overrides_restrictbuts(bmain, block, region, space_outliner, &te->subtree, x);
2020 }
2021
2022 if (!outliner_is_element_in_view(te, &region->v2d)) {
2023 continue;
2024 }
2026 if (!te_id) {
2027 continue;
2028 }
2029
2030 ID &id = te_id->get_ID();
2031 if (ID_IS_LINKED(&id)) {
2032 continue;
2033 }
2034 if (!ID_IS_OVERRIDE_LIBRARY(&id)) {
2035 /* Some items may not be liboverrides, e.g. the root item for all linked libraries (see
2036 * #TreeDisplayOverrideLibraryHierarchies::build_tree). */
2037 continue;
2038 }
2039
2040 const bool is_system_override = BKE_lib_override_library_is_system_defined(bmain, &id);
2041 const BIFIconID icon = is_system_override ? ICON_LIBRARY_DATA_OVERRIDE_NONEDITABLE :
2042 ICON_LIBRARY_DATA_OVERRIDE;
2043 uiBut *but = uiDefIconButO(block,
2045 "ED_OT_lib_id_override_editable_toggle",
2047 icon,
2048 x,
2049 te->ys,
2050 UI_UNIT_X,
2051 UI_UNIT_Y,
2052 "");
2053 /* "id" is used by the operator #ED_OT_lib_id_override_editable_toggle. */
2054 PointerRNA idptr = RNA_id_pointer_create(&id);
2055 UI_but_context_ptr_set(block, but, "id", &idptr);
2056
2057 /* "session_uid" is used to compare buttons (in redraws). */
2058 UI_but_context_int_set(block, but, "session_uid", id.session_uid);
2060
2062 }
2063}
2064
2065static void outliner_draw_separator(ARegion *region, const int x)
2066{
2067 View2D *v2d = &region->v2d;
2068
2069 GPU_line_width(1.0f);
2070
2072 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
2075
2077
2078 immVertex2f(pos, x, v2d->cur.ymax);
2079 immVertex2f(pos, x, v2d->cur.ymin);
2080
2081 immEnd();
2082
2084}
2085
2087 ARegion *region,
2088 SpaceOutliner *space_outliner,
2089 int sizex)
2090{
2092 PropertyRNA *prop;
2093
2094 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2095 TreeStoreElem *tselem = TREESTORE(te);
2096
2097 if (!outliner_is_element_in_view(te, &region->v2d)) {
2098 return;
2099 }
2100
2102 ptr = te_rna_prop->get_pointer_rna();
2103 prop = te_rna_prop->get_property_rna();
2104
2105 if (!TSELEM_OPEN(tselem, space_outliner)) {
2106 if (RNA_property_type(prop) == PROP_POINTER) {
2107 uiBut *but = uiDefAutoButR(block,
2108 &ptr,
2109 prop,
2110 -1,
2111 "",
2112 ICON_NONE,
2113 sizex,
2114 te->ys,
2116 UI_UNIT_Y - 1);
2118 }
2119 else if (RNA_property_type(prop) == PROP_ENUM) {
2120 uiDefAutoButR(block,
2121 &ptr,
2122 prop,
2123 -1,
2124 std::nullopt,
2125 ICON_NONE,
2126 sizex,
2127 te->ys,
2129 UI_UNIT_Y - 1);
2130 }
2131 else {
2132 uiDefAutoButR(block,
2133 &ptr,
2134 prop,
2135 -1,
2136 "",
2137 ICON_NONE,
2138 sizex,
2139 te->ys,
2141 UI_UNIT_Y - 1);
2142 }
2143 }
2144 }
2145 else if (TreeElementRNAArrayElement *te_rna_array_elem =
2147 {
2148 ptr = te_rna_array_elem->get_pointer_rna();
2149 prop = te_rna_array_elem->get_property_rna();
2150
2151 uiDefAutoButR(block,
2152 &ptr,
2153 prop,
2154 te->index,
2155 "",
2156 ICON_NONE,
2157 sizex,
2158 te->ys,
2160 UI_UNIT_Y - 1);
2161 }
2162 });
2163}
2164
2165static void outliner_buttons(const bContext *C,
2166 uiBlock *block,
2167 ARegion *region,
2168 const float restrict_column_width,
2169 TreeElement *te)
2170{
2171 uiBut *bt;
2172 TreeStoreElem *tselem;
2173 int spx, dx, len;
2174
2175 tselem = TREESTORE(te);
2176
2177 BLI_assert(tselem->flag & TSE_TEXTBUT);
2178 /* If we add support to rename Sequence, need change this. */
2179
2180 if (tselem->type == TSE_EBONE) {
2181 len = sizeof(EditBone::name);
2182 }
2183 else if (tselem->type == TSE_MODIFIER) {
2184 len = sizeof(ModifierData::name);
2185 }
2186 else if (tselem->id && GS(tselem->id->name) == ID_LI) {
2187 len = sizeof(Library::filepath);
2188 }
2189 else {
2190 len = MAX_ID_NAME - 2;
2191 }
2192
2193 spx = te->xs + 1.8f * UI_UNIT_X;
2194 dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X);
2195
2196 bt = uiDefBut(block,
2199 "",
2200 spx,
2201 te->ys,
2202 dx,
2203 UI_UNIT_Y - 1,
2204 (void *)te->name,
2205 1.0,
2206 float(len),
2207 "");
2208 /* Handle undo through the #template_id_cb set below. Default undo handling from the button
2209 * code (see #ui_apply_but_undo) would not work here, as the new name is not yet applied to the
2210 * ID. */
2213
2214 /* Returns false if button got removed. */
2215 if (false == UI_but_active_only(C, region, block, bt)) {
2216 tselem->flag &= ~TSE_TEXTBUT;
2217
2218 /* Bad! (notifier within draw) without this, we don't get a refresh. */
2220 }
2221}
2222
2223static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void * /*arg2*/)
2224{
2225 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2226 TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin;
2227 TreeViewContext tvc;
2229
2230 TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
2231 if (!te) {
2232 return;
2233 }
2234
2235 /* Check that the item is actually an object. */
2236 BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
2237
2238 Object *ob = (Object *)tselem->id;
2239 const bool object_data_shared = (ob->data == tvc.obact->data);
2240
2241 wmWindow *win = CTX_wm_window(C);
2242 const bool do_extend = (win->eventstate->modifier & KM_CTRL) && !object_data_shared;
2243 outliner_item_mode_toggle(C, tvc, te, do_extend);
2244}
2245
2246/* Draw icons for adding and removing objects from the current interaction mode. */
2248 const TreeViewContext &tvc,
2249 TreeElement *te,
2250 const bool lock_object_modes)
2251{
2252 TreeStoreElem *tselem = TREESTORE(te);
2253 if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) {
2254 return;
2255 }
2256
2257 Object *ob = (Object *)tselem->id;
2258 Object *ob_active = tvc.obact;
2259 const int x_pad = 3 * UI_SCALE_FAC;
2260
2261 /* Not all objects support particle systems. */
2262 if (ob_active->mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) {
2263 return;
2264 }
2265
2266 /* Only for objects with the same type. */
2267 if (ob->type != ob_active->type) {
2268 return;
2269 }
2270
2271 if (ob->mode == OB_MODE_OBJECT && BKE_object_is_in_editmode(ob)) {
2272 /* Another object has our (shared) data in edit mode, so nothing we can change. */
2273 uiBut *but = uiDefIconBut(block,
2275 0,
2276 UI_icon_from_object_mode(ob_active->mode),
2277 x_pad,
2278 te->ys,
2279 UI_UNIT_X,
2280 UI_UNIT_Y,
2281 nullptr,
2282 0.0,
2283 0.0,
2284 TIP_("Another object has this shared data in edit mode"));
2286 return;
2287 }
2288
2289 bool draw_active_icon = ob->mode == ob_active->mode;
2290
2291 /* When not locking object modes, objects can remain in non-object modes. For modes that do not
2292 * allow multi-object editing, these other objects should still show be viewed as not in the
2293 * mode. Otherwise multiple objects show the same mode icon in the outliner even though only
2294 * one object is actually editable in the mode. */
2295 if (!lock_object_modes && ob != ob_active && !(tvc.ob_edit || tvc.ob_pose)) {
2296 draw_active_icon = false;
2297 }
2298
2299 const bool object_data_shared = (ob->data == ob_active->data);
2300 draw_active_icon = draw_active_icon || object_data_shared;
2301
2302 int icon;
2303 StringRef tip;
2304 if (draw_active_icon) {
2305 icon = UI_icon_from_object_mode(ob_active->mode);
2306 tip = object_data_shared ? TIP_("Change the object in the current mode") :
2307 TIP_("Remove from the current mode");
2308 }
2309 else {
2310 icon = ICON_DOT;
2311 tip = TIP_(
2312 "Change the object in the current mode\n"
2313 " \u2022 Ctrl to add to the current mode");
2314 }
2316 uiBut *but = uiDefIconBut(block,
2318 0,
2319 icon,
2320 x_pad,
2321 te->ys,
2322 UI_UNIT_X,
2323 UI_UNIT_Y,
2324 nullptr,
2325 0.0,
2326 0.0,
2327 tip);
2328 UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
2330 /* Mode toggling handles its own undo state because undo steps need to be grouped. */
2332
2333 if (!ID_IS_EDITABLE(&ob->id) ||
2336 {
2337 UI_but_disable(but, "Cannot edit library or non-editable override data");
2338 }
2339}
2340
2342 TreeViewContext &tvc,
2343 SpaceOutliner *space_outliner)
2344{
2345 const bool lock_object_modes = tvc.scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
2346
2347 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2348 if (tvc.obact && tvc.obact->mode != OB_MODE_OBJECT) {
2349 outliner_draw_mode_column_toggle(block, tvc, te, lock_object_modes);
2350 }
2351 });
2352}
2353
2355{
2356 LISTBASE_FOREACH (const TreeElement *, sub_te, &parent_te->subtree) {
2358 StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2359
2360 if (!warning_msg.is_empty()) {
2361 return warning_msg;
2362 }
2363
2365 if (!warning_msg.is_empty()) {
2366 return warning_msg;
2367 }
2368 }
2369
2370 return "";
2371}
2372
2374 const TreeElement *te)
2375{
2377 const StringRefNull warning_msg = abstract_te ? abstract_te->get_warning() : "";
2378
2379 if (!warning_msg.is_empty()) {
2380 return warning_msg;
2381 }
2382
2383 /* If given element has no warning, recursively try to display the first sub-element's warning.
2384 */
2385 if (!TSELEM_OPEN(te->store_elem, &space_outliner)) {
2387 }
2388
2389 return "";
2390}
2391
2393 const SpaceOutliner *space_outliner,
2394 const StringRef warning_msg,
2395 const bool use_mode_column,
2396 const int te_ys)
2397{
2398 /* Move the warnings a unit left in view layer mode. */
2399 const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
2400 UI_UNIT_X :
2401 0;
2402
2404 uiBut *but = uiDefIconBut(block,
2406 0,
2407 ICON_ERROR,
2408 mode_column_offset,
2409 te_ys,
2410 UI_UNIT_X,
2411 UI_UNIT_Y,
2412 nullptr,
2413 0.0,
2414 0.0,
2415 warning_msg);
2416 /* No need for undo here, this is a pure info widget. */
2418}
2419
2421 const SpaceOutliner *space_outliner,
2422 const bool use_mode_column)
2423{
2424 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
2425 /* Get warning for this element, or if there is none and the element is collapsed, the first
2426 * warning in the collapsed sub-tree. */
2427 StringRefNull warning_msg = outliner_draw_get_warning_tree_element(*space_outliner, te);
2428
2429 if (!warning_msg.is_empty()) {
2431 block, space_outliner, warning_msg, use_mode_column, te->ys);
2432 }
2433 });
2434}
2435
2437
2438/* -------------------------------------------------------------------- */
2441
2443{
2444 if (GS(id->name) == ID_OB) {
2445 const Object *ob = (Object *)id;
2446 switch (ob->type) {
2447 case OB_LAMP:
2448 return ICON_OUTLINER_OB_LIGHT;
2449 case OB_MESH:
2450 return ICON_OUTLINER_OB_MESH;
2451 case OB_CAMERA:
2452 return ICON_OUTLINER_OB_CAMERA;
2453 case OB_CURVES_LEGACY:
2454 return ICON_OUTLINER_OB_CURVE;
2455 case OB_MBALL:
2456 return ICON_OUTLINER_OB_META;
2457 case OB_LATTICE:
2458 return ICON_OUTLINER_OB_LATTICE;
2459 case OB_ARMATURE:
2460 return ICON_OUTLINER_OB_ARMATURE;
2461 case OB_FONT:
2462 return ICON_OUTLINER_OB_FONT;
2463 case OB_SURF:
2464 return ICON_OUTLINER_OB_SURFACE;
2465 case OB_SPEAKER:
2466 return ICON_OUTLINER_OB_SPEAKER;
2467 case OB_LIGHTPROBE:
2468 return ICON_OUTLINER_OB_LIGHTPROBE;
2469 case OB_CURVES:
2470 return ICON_OUTLINER_OB_CURVES;
2471 case OB_POINTCLOUD:
2472 return ICON_OUTLINER_OB_POINTCLOUD;
2473 case OB_VOLUME:
2474 return ICON_OUTLINER_OB_VOLUME;
2475 case OB_EMPTY:
2477 return ICON_OUTLINER_OB_GROUP_INSTANCE;
2478 }
2479 else if (ob->empty_drawtype == OB_EMPTY_IMAGE) {
2480 return ICON_OUTLINER_OB_IMAGE;
2481 }
2482 else if (ob->pd && ob->pd->forcefield) {
2483 return ICON_OUTLINER_OB_FORCE_FIELD;
2484 }
2485 else {
2486 return ICON_OUTLINER_OB_EMPTY;
2487 }
2488 case OB_GREASE_PENCIL:
2489 return ICON_OUTLINER_OB_GREASEPENCIL;
2490 }
2491
2492 return ICON_NONE;
2493 }
2494
2495 /* TODO(sergey): Casting to short here just to handle ID_NLA which is
2496 * NOT inside of IDType enum.
2497 */
2498 switch (short(GS(id->name))) {
2499 case ID_SCE:
2500 return ICON_SCENE_DATA;
2501 case ID_ME:
2502 return ICON_OUTLINER_DATA_MESH;
2503 case ID_CU_LEGACY: {
2504 const Curve *cu = (Curve *)id;
2505 switch (cu->ob_type) {
2506 case OB_FONT:
2507 return ICON_OUTLINER_DATA_FONT;
2508 case OB_SURF:
2509 return ICON_OUTLINER_DATA_SURFACE;
2510 default:
2511 return ICON_OUTLINER_DATA_CURVE;
2512 }
2513 break;
2514 }
2515 case ID_MB:
2516 return ICON_OUTLINER_DATA_META;
2517 case ID_LT:
2518 return ICON_OUTLINER_DATA_LATTICE;
2519 case ID_LA: {
2520 const Light *la = (Light *)id;
2521 switch (la->type) {
2522 case LA_LOCAL:
2523 return ICON_LIGHT_POINT;
2524 case LA_SUN:
2525 return ICON_LIGHT_SUN;
2526 case LA_SPOT:
2527 return ICON_LIGHT_SPOT;
2528 case LA_AREA:
2529 return ICON_LIGHT_AREA;
2530 default:
2531 return ICON_OUTLINER_DATA_LIGHT;
2532 }
2533 }
2534 case ID_MA:
2535 return ICON_MATERIAL_DATA;
2536 case ID_TE:
2537 return ICON_TEXTURE_DATA;
2538 case ID_IM:
2539 return ICON_IMAGE_DATA;
2540 case ID_SPK:
2541 case ID_SO:
2542 return ICON_OUTLINER_DATA_SPEAKER;
2543 case ID_AR:
2544 return ICON_OUTLINER_DATA_ARMATURE;
2545 case ID_CA:
2546 return ICON_OUTLINER_DATA_CAMERA;
2547 case ID_KE:
2548 return ICON_SHAPEKEY_DATA;
2549 case ID_WO:
2550 return ICON_WORLD_DATA;
2551 case ID_AC:
2552 return ICON_ACTION;
2553 case ID_NLA:
2554 return ICON_NLA;
2555 case ID_TXT: {
2556 const Text *text = (Text *)id;
2557 if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
2558 return ICON_FILE_TEXT;
2559 }
2560 /* Helps distinguish text-based formats like the file-browser does. */
2561 return ED_file_extension_icon(text->filepath);
2562 }
2563 case ID_GR:
2564 return ICON_OUTLINER_COLLECTION;
2565 case ID_CV:
2566 return ICON_OUTLINER_DATA_CURVES;
2567 case ID_PT:
2568 return ICON_OUTLINER_DATA_POINTCLOUD;
2569 case ID_VO:
2570 return ICON_OUTLINER_DATA_VOLUME;
2571 case ID_LI:
2572 if (id->tag & ID_TAG_MISSING) {
2573 return ICON_LIBRARY_DATA_BROKEN;
2574 }
2575 else if (reinterpret_cast<const Library *>(id)->flag & LIBRARY_FLAG_IS_ARCHIVE) {
2576 return ICON_PACKAGE;
2577 }
2578 else if (((Library *)id)->runtime->parent) {
2579 return ICON_LIBRARY_DATA_INDIRECT;
2580 }
2581 else {
2582 return ICON_LIBRARY_DATA_DIRECT;
2583 }
2584 case ID_LS:
2585 return ICON_LINE_DATA;
2586 case ID_GP:
2587 case ID_GD_LEGACY:
2588 return ICON_OUTLINER_DATA_GREASEPENCIL;
2589 case ID_LP: {
2590 const LightProbe *lp = (LightProbe *)id;
2591 switch (lp->type) {
2593 return ICON_LIGHTPROBE_SPHERE;
2595 return ICON_LIGHTPROBE_PLANE;
2597 return ICON_LIGHTPROBE_VOLUME;
2598 default:
2599 return ICON_LIGHTPROBE_SPHERE;
2600 }
2601 }
2602 case ID_BR:
2603 return ICON_BRUSH_DATA;
2604 case ID_SCR:
2605 case ID_WS:
2606 return ICON_WORKSPACE;
2607 case ID_MSK:
2608 return ICON_MOD_MASK;
2609 case ID_NT: {
2610 const bNodeTree *ntree = (bNodeTree *)id;
2611 const bke::bNodeTreeType *ntreetype = ntree->typeinfo;
2612 return ntreetype->ui_icon;
2613 }
2614 case ID_MC:
2615 return ICON_SEQUENCE;
2616 case ID_PC:
2617 return ICON_CURVE_BEZCURVE;
2618 case ID_PA:
2619 return ICON_PARTICLES;
2620 case ID_PAL:
2621 return ICON_COLOR;
2622 case ID_VF:
2623 return ICON_FILE_FONT;
2624 default:
2625 return ICON_NONE;
2626 }
2627}
2628
2630{
2631 TreeElementIcon data = {nullptr};
2632
2633 if (tselem->type != TSE_SOME_ID) {
2634 switch (tselem->type) {
2635 case TSE_ACTION_SLOT:
2636 data.icon = ICON_ACTION_SLOT;
2637 break;
2638 case TSE_ANIM_DATA:
2639 data.icon = ICON_ANIM_DATA; /* XXX */
2640 break;
2641 case TSE_NLA:
2642 data.icon = ICON_NLA;
2643 break;
2644 case TSE_NLA_TRACK:
2645 data.icon = ICON_NLA; /* XXX */
2646 break;
2647 case TSE_NLA_ACTION:
2648 data.icon = ICON_ACTION;
2649 break;
2650 case TSE_DRIVER_BASE:
2651 data.icon = ICON_DRIVER;
2652 break;
2653 case TSE_DEFGROUP_BASE:
2654 data.icon = ICON_GROUP_VERTEX;
2655 break;
2656 case TSE_DEFGROUP:
2657 data.icon = ICON_GROUP_VERTEX;
2658 break;
2659 case TSE_BONE:
2660 case TSE_EBONE:
2661 data.icon = ICON_BONE_DATA;
2662 break;
2664 data.icon = ICON_CONSTRAINT;
2665 data.drag_id = tselem->id;
2666 break;
2667 case TSE_CONSTRAINT: {
2668 bConstraint *con = static_cast<bConstraint *>(te->directdata);
2669 data.drag_id = tselem->id;
2670 switch ((eBConstraint_Types)con->type) {
2672 data.icon = ICON_CON_CAMERASOLVER;
2673 break;
2675 data.icon = ICON_CON_FOLLOWTRACK;
2676 break;
2678 data.icon = ICON_CON_OBJECTSOLVER;
2679 break;
2681 data.icon = ICON_CON_LOCLIKE;
2682 break;
2684 data.icon = ICON_CON_ROTLIKE;
2685 break;
2687 data.icon = ICON_CON_SIZELIKE;
2688 break;
2690 data.icon = ICON_CON_TRANSLIKE;
2691 break;
2693 data.icon = ICON_CON_DISTLIMIT;
2694 break;
2696 data.icon = ICON_CON_LOCLIMIT;
2697 break;
2699 data.icon = ICON_CON_ROTLIMIT;
2700 break;
2702 data.icon = ICON_CON_SIZELIMIT;
2703 break;
2705 data.icon = ICON_CON_SAMEVOL;
2706 break;
2708 data.icon = ICON_CON_TRANSFORM;
2709 break;
2711 data.icon = ICON_CON_TRANSFORM_CACHE;
2712 break;
2714 data.icon = ICON_CON_CLAMPTO;
2715 break;
2717 data.icon = ICON_CON_TRACKTO;
2718 break;
2720 data.icon = ICON_CON_KINEMATIC;
2721 break;
2723 data.icon = ICON_CON_LOCKTRACK;
2724 break;
2726 data.icon = ICON_CON_SPLINEIK;
2727 break;
2729 data.icon = ICON_CON_STRETCHTO;
2730 break;
2732 data.icon = ICON_CON_TRACKTO;
2733 break;
2735 data.icon = ICON_CON_ACTION;
2736 break;
2738 data.icon = ICON_CON_ARMATURE;
2739 break;
2741 data.icon = ICON_CON_CHILDOF;
2742 break;
2744 data.icon = ICON_CON_FLOOR;
2745 break;
2747 data.icon = ICON_CON_FOLLOWPATH;
2748 break;
2750 data.icon = ICON_CON_PIVOT;
2751 break;
2753 data.icon = ICON_CON_SHRINKWRAP;
2754 break;
2756 data.icon = ICON_CON_GEOMETRYATTRIBUTE;
2757 break;
2758
2759 default:
2760 data.icon = ICON_DOT;
2761 break;
2762 }
2763 break;
2764 }
2765 case TSE_MODIFIER_BASE:
2766 data.icon = ICON_MODIFIER_DATA;
2767 data.drag_id = tselem->id;
2768 break;
2771 data.icon = tree_element_get_icon_from_id(&base_te->id);
2772 break;
2773 }
2775 data.icon = ICON_LIBRARY_DATA_OVERRIDE;
2776 break;
2777 case TSE_LINKED_OB:
2778 data.icon = ICON_OBJECT_DATA;
2779 break;
2780 case TSE_LINKED_PSYS:
2781 data.icon = ICON_PARTICLES;
2782 break;
2783 case TSE_MODIFIER: {
2784 Object *ob = (Object *)tselem->id;
2785 data.drag_id = tselem->id;
2786
2787 ModifierData *md = static_cast<ModifierData *>(BLI_findlink(&ob->modifiers, tselem->nr));
2788 if (const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(ModifierType(md->type)))
2789 {
2790 data.icon = modifier_type->icon;
2791 }
2792 else {
2793 data.icon = ICON_DOT;
2794 }
2795 break;
2796 }
2798 data.icon = ICON_NODETREE;
2799 break;
2800 case TSE_POSE_BASE:
2801 data.icon = ICON_ARMATURE_DATA;
2802 break;
2803 case TSE_POSE_CHANNEL:
2804 data.icon = ICON_BONE_DATA;
2805 break;
2806 case TSE_R_LAYER_BASE:
2807 data.icon = ICON_RENDERLAYERS;
2808 break;
2810 data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE;
2811 break;
2812 case TSE_R_LAYER:
2813 data.icon = ICON_RENDER_RESULT;
2814 break;
2817 data.icon = ICON_GROUP_BONE;
2818 break;
2819 case TSE_STRIP: {
2821 switch (te_strip->get_strip_type()) {
2822 case STRIP_TYPE_SCENE:
2823 data.icon = ICON_SCENE_DATA;
2824 break;
2826 data.icon = ICON_TRACKER;
2827 break;
2828 case STRIP_TYPE_MASK:
2829 data.icon = ICON_MOD_MASK;
2830 break;
2831 case STRIP_TYPE_MOVIE:
2832 data.icon = ICON_FILE_MOVIE;
2833 break;
2835 data.icon = ICON_SOUND;
2836 break;
2837 case STRIP_TYPE_IMAGE:
2838 data.icon = ICON_FILE_IMAGE;
2839 break;
2840 case STRIP_TYPE_COLOR:
2842 data.icon = ICON_COLOR;
2843 break;
2844 case STRIP_TYPE_TEXT:
2845 data.icon = ICON_FONT_DATA;
2846 break;
2847 case STRIP_TYPE_ADD:
2848 case STRIP_TYPE_SUB:
2849 case STRIP_TYPE_MUL:
2854 case STRIP_TYPE_SPEED:
2855 case STRIP_TYPE_GLOW:
2857 data.icon = ICON_SHADERFX;
2858 break;
2859 case STRIP_TYPE_CROSS:
2861 case STRIP_TYPE_WIPE:
2862 data.icon = ICON_ARROW_LEFTRIGHT;
2863 break;
2864 case STRIP_TYPE_META:
2865 data.icon = ICON_SEQ_STRIP_META;
2866 break;
2867 default:
2868 data.icon = ICON_DOT;
2869 break;
2870 }
2871 break;
2872 }
2873 case TSE_STRIP_DATA:
2874 data.icon = ICON_LIBRARY_DATA_DIRECT;
2875 break;
2876 case TSE_STRIP_DUP:
2877 data.icon = ICON_SEQ_STRIP_DUPLICATE;
2878 break;
2879 case TSE_RNA_STRUCT: {
2881 const PointerRNA &ptr = te_rna_struct->get_pointer_rna();
2882
2883 if (RNA_struct_is_ID(ptr.type)) {
2884 ID *id = static_cast<ID *>(ptr.data);
2885 data.drag_id = id;
2886 if (id && GS(id->name) == ID_LI &&
2887 id_cast<Library *>(id)->flag & LIBRARY_FLAG_IS_ARCHIVE)
2888 {
2889 data.icon = ICON_PACKAGE;
2890 }
2891 else {
2892 data.icon = RNA_struct_ui_icon(ptr.type);
2893 }
2894 }
2895 else {
2896 data.icon = RNA_struct_ui_icon(ptr.type);
2897 }
2898 break;
2899 }
2904 if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
2905 data.drag_id = tselem->id;
2906 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2907 }
2908
2909 data.icon = ICON_OUTLINER_COLLECTION;
2910 break;
2911 }
2912 case TSE_GP_LAYER: {
2913 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2914 break;
2915 }
2919 if (node.is_layer()) {
2920 data.icon = ICON_OUTLINER_DATA_GP_LAYER;
2921 }
2922 else if (node.is_group()) {
2923 const bke::greasepencil::LayerGroup &group = node.as_group();
2924
2925 data.icon = ICON_GREASEPENCIL_LAYER_GROUP;
2926 if (group.color_tag != LAYERGROUP_COLOR_NONE) {
2927 data.icon = ICON_LAYERGROUP_COLOR_01 + group.color_tag;
2928 }
2929 }
2930 break;
2931 }
2933 case TSE_GPENCIL_EFFECT:
2934 data.drag_id = tselem->id;
2935 data.icon = ICON_SHADERFX;
2936 break;
2937 default:
2938 data.icon = ICON_DOT;
2939 break;
2940 }
2941 }
2942 else if (tselem->id) {
2943 data.drag_id = tselem->id;
2944 data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
2945 data.icon = tree_element_get_icon_from_id(tselem->id);
2946 }
2947
2948 if (!te->abstract_element) {
2949 /* Pass */
2950 }
2951 else if (auto icon = te->abstract_element->get_icon()) {
2952 data.icon = *icon;
2953 }
2954
2955 return data;
2956}
2957
2961static bool tselem_draw_icon(uiBlock *block,
2962 int xmax,
2963 float x,
2964 float y,
2965 TreeStoreElem *tselem,
2966 TreeElement *te,
2967 float alpha,
2968 const bool is_clickable,
2969 const int num_elements)
2970{
2972 if (data.icon == 0) {
2973 return false;
2974 }
2975
2976 const bool is_collection = outliner_is_collection_tree_element(te);
2977 IconTextOverlay text_overlay;
2978 UI_icon_text_overlay_init_from_count(&text_overlay, num_elements);
2979
2980 /* Collection colors and icons covered by restrict buttons. */
2981 if (!is_clickable || x >= xmax || is_collection) {
2982 /* Placement of icons, copied from `interface_widgets.cc`. */
2983 float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
2984 x += 2.0f * aspect;
2985 y += 2.0f * aspect;
2986 bTheme *btheme = UI_GetTheme();
2987
2988 if (is_collection) {
2990 if (collection->color_tag != COLLECTION_COLOR_NONE) {
2992 y,
2993 ICON_COLLECTION_COLOR_01 + collection->color_tag,
2995 alpha,
2996 0.0f,
2997 btheme->collection_color[collection->color_tag].color,
2998 btheme->tui.icon_border_intensity > 0.0f,
2999 &text_overlay);
3000 return true;
3001 }
3002 }
3003
3004 /* Reduce alpha to match icon buttons */
3005 alpha *= 0.8f;
3006
3007 /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */
3008 uchar color[4];
3009 if (UI_icon_get_theme_color(data.icon, color)) {
3011 y,
3012 data.icon,
3014 alpha,
3015 0.0f,
3016 color,
3017 btheme->tui.icon_border_intensity > 0.0f,
3018 &text_overlay);
3019 }
3020 else {
3022 x, y, data.icon, UI_INV_SCALE_FAC, alpha, 0.0f, nullptr, false, &text_overlay);
3023 }
3024 }
3025 else {
3026 uiBut *but = uiDefIconBut(
3027 block,
3029 0,
3030 data.icon,
3031 x,
3032 y,
3033 UI_UNIT_X,
3034 UI_UNIT_Y,
3035 nullptr,
3036 0.0,
3037 0.0,
3038 (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->filepath : "");
3040 }
3041
3042 return true;
3043}
3044
3045static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
3046{
3047 float text[4];
3049
3050 copy_v3_v3(icon_color, text);
3051 icon_color[3] = 0.4f;
3052 copy_v3_v3(icon_border, text);
3053 icon_border[3] = 0.2f;
3054}
3055
3056/* Draw a rounded rectangle behind icons of active elements. */
3057static void outliner_draw_active_indicator(const float minx,
3058 const float miny,
3059 const float maxx,
3060 const float maxy,
3061 const float icon_color[4],
3062 const float icon_border[4])
3063{
3064 const float ufac = UI_UNIT_X / 20.0f;
3065 const float radius = UI_UNIT_Y / 4.0f;
3066 rctf rect{};
3067 BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
3068
3070 UI_draw_roundbox_aa(&rect, true, radius, icon_color);
3071 UI_draw_roundbox_aa(&rect, false, radius, icon_border);
3072 GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */
3073}
3074
3076 TreeElement *te,
3077 int xmax,
3078 int *offsx,
3079 int ys,
3080 float alpha_fac,
3081 const eOLDrawState active,
3082 const int num_elements)
3083{
3084 TreeStoreElem *tselem = TREESTORE(te);
3085
3086 if (active != OL_DRAWSEL_NONE) {
3087 float icon_color[4], icon_border[4];
3088 outliner_icon_background_colors(icon_color, icon_border);
3089 if (active == OL_DRAWSEL_ACTIVE) {
3091 icon_border[3] = 0.3f;
3092 }
3093
3094 outliner_draw_active_indicator(float(*offsx),
3095 float(ys),
3096 float(*offsx) + UI_UNIT_X,
3097 float(ys) + UI_UNIT_Y,
3098 icon_color,
3099 icon_border);
3100 }
3101
3102 if (tselem->flag & TSE_HIGHLIGHTED_ICON) {
3103 alpha_fac += 0.5;
3104 }
3106 block, xmax, float(*offsx), float(ys), tselem, te, alpha_fac, false, num_elements);
3107 te->xs = *offsx;
3108 te->ys = ys;
3109 te->xend = short(*offsx) + UI_UNIT_X;
3110
3111 if (num_elements > 1) {
3112 te->flag |= TE_ICONROW_MERGED;
3113 }
3114 else {
3115 te->flag |= TE_ICONROW;
3116 }
3117
3118 (*offsx) += UI_UNIT_X;
3119}
3120
3122{
3123 TreeStoreElem *tselem = TREESTORE(te);
3124
3125 int id_index = 0;
3126 if (tselem->type == TSE_SOME_ID) {
3127 id_index = BKE_idtype_idcode_to_index(te->idcode);
3128 }
3129 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3130 /* Use the index of the grease pencil ID for the grease pencil tree nodes (which are not IDs).
3131 * All the Grease Pencil layer tree stats are stored in this index in #MergedIconRow. */
3132 id_index = INDEX_ID_GP;
3133 }
3134 else {
3135 id_index = INDEX_ID_GR;
3136 }
3137
3138 if (id_index < INDEX_ID_OB) {
3139 return id_index;
3140 }
3141 if (id_index == INDEX_ID_OB) {
3142 const Object *ob = (Object *)tselem->id;
3143 return INDEX_ID_OB + ob->type;
3144 }
3145 return id_index + OB_TYPE_MAX;
3146}
3147
3153
3155 const uiFontStyle *fstyle,
3156 const TreeViewContext &tvc,
3157 SpaceOutliner *space_outliner,
3158 ListBase *lb,
3159 int level,
3160 int xmax,
3161 int *offsx,
3162 int ys,
3163 float alpha_fac,
3164 bool in_bone_hierarchy,
3165 const bool is_grease_pencil_node_hierarchy,
3166 MergedIconRow *merged)
3167{
3169
3170 LISTBASE_FOREACH (TreeElement *, te, lb) {
3171 TreeStoreElem *tselem = TREESTORE(te);
3172 te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED);
3173
3174 /* object hierarchy always, further constrained on level */
3175 /* Bones are also hierarchies and get a merged count, but we only start recursing into them if
3176 * an they are at the root level of a collapsed subtree (e.g. not "hidden" in a collapsed
3177 * collection). */
3178 const bool is_bone = ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL);
3179 /* The Grease Pencil layer tree is a hierarchy where we merge and count the total number of
3180 * layers in a node. We merge the counts for all the layers and skip counting nodes that are
3181 * layer groups (for less visual clutter in the outliner). */
3182 const bool is_grease_pencil_node = (tselem->type == TSE_GREASE_PENCIL_NODE);
3183 if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) ||
3184 (is_grease_pencil_node_hierarchy && is_grease_pencil_node) ||
3185 (in_bone_hierarchy && is_bone))
3186 {
3187 /* active blocks get white circle */
3188 if (tselem->type == TSE_SOME_ID) {
3189 if (te->idcode == ID_OB) {
3190 active = (tvc.obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
3191 }
3192 else if (is_object_data_in_editmode(tselem->id, tvc.obact)) {
3194 }
3195 else {
3196 active = tree_element_active_state_get(tvc, te, tselem);
3197 }
3198 }
3199 else {
3200 active = tree_element_type_active_state_get(tvc, te, tselem);
3201 }
3202
3203 if (!ELEM(tselem->type,
3213 TSE_BONE,
3214 TSE_EBONE,
3220 {
3221 outliner_draw_iconrow_doit(block, te, xmax, offsx, ys, alpha_fac, active, 1);
3222 }
3223 else if (tselem->type == TSE_GREASE_PENCIL_NODE &&
3225 {
3226 /* Grease Pencil layer groups are tree nodes, but they shouldn't be counted. We only want
3227 * to keep track of the nodes that are layers and show the total number of layers in a
3228 * node. Adding the count of groups would add a lot of clutter. */
3229 }
3230 else {
3231 const int index = tree_element_id_type_to_index(te);
3232 merged->num_elements[index]++;
3233 if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
3234 merged->tree_element[index] = te;
3235 }
3236 merged->active[index] = std::max(active, merged->active[index]);
3237 }
3238 }
3239
3240 /* TSE_R_LAYER tree element always has same amount of branches, so don't draw. */
3241 /* Also only recurse into bone hierarchies if a direct child of the collapsed element to
3242 * merge into. */
3243 const bool is_root_level_bone = is_bone && (level == 0);
3244 in_bone_hierarchy |= is_root_level_bone;
3245 /* Recurse into the grease pencil layer tree if we already are in the hierarchy or if we're at
3246 * the root level and find a grease pencil node. */
3247 const bool in_grease_pencil_node_hierarchy = is_grease_pencil_node_hierarchy ||
3248 (is_grease_pencil_node && level == 0);
3250 in_bone_hierarchy || in_grease_pencil_node_hierarchy)
3251 {
3253 fstyle,
3254 tvc,
3255 space_outliner,
3256 &te->subtree,
3257 level + 1,
3258 xmax,
3259 offsx,
3260 ys,
3261 alpha_fac,
3262 in_bone_hierarchy,
3263 in_grease_pencil_node_hierarchy,
3264 merged);
3265 }
3266 }
3267
3268 if (level == 0) {
3269 for (int i = 0; i < INDEX_ID_MAX; i++) {
3270 const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1;
3271 /* See tree_element_id_type_to_index for the index logic. */
3272 int index_base = i;
3273 if (i > INDEX_ID_OB) {
3274 index_base += OB_TYPE_MAX;
3275 }
3276 for (int j = 0; j < num_subtypes; j++) {
3277 const int index = index_base + j;
3278 if (merged->num_elements[index] != 0) {
3280 merged->tree_element[index],
3281 xmax,
3282 offsx,
3283 ys,
3284 alpha_fac,
3285 merged->active[index],
3286 merged->num_elements[index]);
3287 }
3288 }
3289 }
3290 }
3291}
3292
3293/* closed tree element */
3295{
3296 tree_iterator::all(te->subtree, [&](TreeElement *te) {
3297 /* closed items may be displayed in row of parent, don't change their coordinate! */
3298 if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
3299 te->xs = 0;
3300 te->ys = 0;
3301 te->xend = 0;
3302 }
3303 });
3304}
3305
3307 const TreeElement *te,
3308 const TreeStoreElem *tselem)
3309{
3310 if (tselem->type == TSE_SOME_ID) {
3311 switch (te->idcode) {
3312 case ID_OB: {
3313 const Object *ob = (const Object *)tselem->id;
3314 /* Lookup in view layer is logically const as it only checks a cache. */
3316 const Base *base = (te->directdata) ?
3317 (const Base *)te->directdata :
3319 const bool is_visible = (base != nullptr) &&
3322
3323 return !is_visible;
3324 }
3325 default: {
3326 if (te->parent) {
3327 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3328 }
3329 }
3330 }
3331 }
3332 switch (tselem->type) {
3333 case TSE_LAYER_COLLECTION: {
3334 const LayerCollection *layer_collection = (const LayerCollection *)te->directdata;
3335 const bool is_visible = layer_collection->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER;
3336 const bool is_excluded = layer_collection->flag & LAYER_COLLECTION_EXCLUDE;
3337 return !is_visible || is_excluded;
3338 }
3342 return !node.is_visible();
3343 }
3344 default: {
3345 if (te->parent) {
3346 return element_should_draw_faded(tvc, te->parent, te->parent->store_elem);
3347 }
3348 }
3349 }
3350
3351 if (te->flag & TE_CHILD_NOT_IN_COLLECTION) {
3352 return true;
3353 }
3354
3355 return false;
3356}
3357
3359 const uiFontStyle *fstyle,
3360 const TreeViewContext &tvc,
3361 ARegion *region,
3362 SpaceOutliner *space_outliner,
3363 TreeElement *te,
3364 bool draw_grayed_out,
3365 int startx,
3366 int *starty,
3367 const float restrict_column_width,
3368 TreeElement **te_edit)
3369{
3370 TreeStoreElem *tselem = TREESTORE(te);
3371 float ufac = UI_UNIT_X / 20.0f;
3372 int offsx = 0;
3374 uchar text_color[4];
3375 UI_GetThemeColor4ubv(TH_TEXT, text_color);
3376 float icon_bgcolor[4], icon_border[4];
3377 outliner_icon_background_colors(icon_bgcolor, icon_border);
3378
3379 if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) {
3380 const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
3381 int xmax = region->v2d.cur.xmax;
3382
3383 if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
3384 *te_edit = te;
3385 }
3386
3387 /* Icons can be UI buts, we don't want it to overlap with restrict. */
3388 if (restrict_column_width > 0) {
3389 xmax -= restrict_column_width + UI_UNIT_X;
3390 }
3391
3393
3394 /* Colors for active/selected data. */
3395 if (tselem->type == TSE_SOME_ID) {
3396 if (te->idcode == ID_OB) {
3397 Object *ob = (Object *)tselem->id;
3399 Base *base = (te->directdata) ? (Base *)te->directdata :
3401 const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
3402
3403 if (ob == tvc.obact) {
3405 }
3406
3407 if (is_selected) {
3408 if (ob == tvc.obact) {
3409 /* Active selected object. */
3411 text_color[3] = 255;
3412 }
3413 else {
3414 /* Other selected objects. */
3416 text_color[3] = 255;
3417 }
3418 }
3419 }
3420 else if (is_object_data_in_editmode(tselem->id, tvc.obact)) {
3421 /* Objects being edited. */
3423 icon_border[3] = 0.3f;
3425 }
3426 else {
3427 if (tree_element_active_state_get(tvc, te, tselem)) {
3428 /* Active items like camera or material. */
3429 icon_bgcolor[3] = 0.2f;
3431 if (te->idcode == ID_SCE) {
3432 UI_GetThemeColor3ubv(TH_TEXT_HI, text_color);
3433 text_color[3] = 255;
3434 }
3435 }
3436 }
3437 }
3438 else {
3439 active = tree_element_type_active_state_get(tvc, te, tselem);
3440 if (active != OL_DRAWSEL_NONE) {
3441 UI_GetThemeColor3ubv(TH_TEXT_HI, text_color);
3442 text_color[3] = 255;
3443 }
3444 }
3445
3446 /* Active circle. */
3447 if (active != OL_DRAWSEL_NONE) {
3448 outliner_draw_active_indicator(float(startx) + offsx + UI_UNIT_X,
3449 float(*starty),
3450 float(startx) + offsx + 2.0f * UI_UNIT_X,
3451 float(*starty) + UI_UNIT_Y,
3452 icon_bgcolor,
3453 icon_border);
3454
3455 te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */
3456 }
3457
3458 if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
3459 /* Scene collection in view layer can't expand/collapse. */
3460 }
3461 else if (te->subtree.first || (te->flag & TE_PRETEND_HAS_CHILDREN)) {
3462 /* Open/close icon, only when sub-levels, except for scene. */
3463 int icon_x = startx;
3464
3465 /* Icons a bit higher. */
3466 if (TSELEM_OPEN(tselem, space_outliner)) {
3468 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_DOWNARROW_HLT, alpha_fac);
3469 }
3470 else {
3472 float(icon_x) + 2 * ufac, float(*starty) + 1 * ufac, ICON_RIGHTARROW, alpha_fac);
3473 }
3474 }
3475 offsx += UI_UNIT_X;
3476
3477 /* Data-type icon. */
3479 tselem_draw_icon(block,
3480 xmax,
3481 float(startx) + offsx,
3482 float(*starty),
3483 tselem,
3484 te,
3485 (tselem->flag & TSE_HIGHLIGHTED_ICON) ? alpha_fac + 0.5f : alpha_fac,
3486 true,
3487 1))
3488 {
3489 offsx += UI_UNIT_X + 4 * ufac;
3490 }
3491 else {
3492 offsx += 2 * ufac;
3493 }
3494
3497 (te_rna_struct && RNA_struct_is_ID(te_rna_struct->get_pointer_rna().type)))
3498 {
3499 const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
3500 if (lib_icon != ICON_NONE) {
3502 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, lib_icon, alpha_fac);
3503 offsx += UI_UNIT_X + 4 * ufac;
3504 }
3505
3506 if (tselem->type == TSE_LAYER_COLLECTION) {
3507 const Collection *collection = (Collection *)tselem->id;
3508 if (!BLI_listbase_is_empty(&collection->exporters)) {
3510 float(startx) + offsx + 2 * ufac, float(*starty) + 2 * ufac, ICON_EXPORT, alpha_fac);
3511 offsx += UI_UNIT_X + 4 * ufac;
3512 }
3513 }
3514 }
3516
3517 /* Name. */
3518 if ((tselem->flag & TSE_TEXTBUT) == 0) {
3520 UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_color);
3521 text_color[3] = 255;
3522 }
3523 text_color[3] *= alpha_fac;
3524 UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_color);
3525 }
3526
3527 offsx += int(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
3528
3529 /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */
3530 if (!TSELEM_OPEN(tselem, space_outliner)) {
3531 if (te->subtree.first) {
3532 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
3533 /* Pass. */
3534 }
3535 /* this tree element always has same amount of branches, so don't draw */
3536 else if (tselem->type != TSE_R_LAYER) {
3537 int tempx = startx + offsx;
3538
3540
3541 MergedIconRow merged{};
3543 fstyle,
3544 tvc,
3545 space_outliner,
3546 &te->subtree,
3547 0,
3548 xmax,
3549 &tempx,
3550 *starty,
3551 alpha_fac,
3552 false,
3553 false,
3554 &merged);
3555
3557 }
3558 }
3559 }
3560 }
3561 /* Store coord and continue, we need coordinates for elements outside view too. */
3562 te->xs = startx;
3563 te->ys = *starty;
3564 te->xend = startx + offsx;
3565
3566 if (TSELEM_OPEN(tselem, space_outliner)) {
3567 *starty -= UI_UNIT_Y;
3568
3569 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
3570 /* Check if element needs to be drawn grayed out, but also gray out
3571 * children of a grayed out parent (pass on draw_grayed_out to children). */
3572 bool draw_children_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
3574 fstyle,
3575 tvc,
3576 region,
3577 space_outliner,
3578 ten,
3579 draw_children_grayed_out,
3580 startx + UI_UNIT_X,
3581 starty,
3582 restrict_column_width,
3583 te_edit);
3584 }
3585 }
3586 else {
3588 *starty -= UI_UNIT_Y;
3589 }
3590}
3591
3593{
3594 LISTBASE_FOREACH (TreeElement *, te, lb) {
3595 TreeStoreElem *tselem = TREESTORE(te);
3596 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3597 return true;
3598 }
3599 }
3600 return false;
3601}
3602
3604 const uint pos, const int x, const int y1, const int y2, const bool draw_dashed)
3605{
3606 /* Small vertical padding. */
3607 const short line_padding = UI_UNIT_Y / 4.0f;
3608
3609 /* >= is 1.0 for un-dashed lines. */
3610 immUniform1f("udash_factor", draw_dashed ? 0.5f : 1.0f);
3611
3613 /* Intentionally draw from top to bottom, so collapsing a child item doesn't make the dashes
3614 * appear to move. */
3615 immVertex2f(pos, x, y2 + line_padding);
3616 immVertex2f(pos, x, y1 - line_padding);
3617 immEnd();
3618}
3619
3621 SpaceOutliner *space_outliner,
3622 ListBase *lb,
3623 const TreeViewContext &tvc,
3624 int startx,
3625 const uchar col[4],
3626 bool draw_grayed_out,
3627 int *starty)
3628{
3629 bTheme *btheme = UI_GetTheme();
3630 int y = *starty;
3631
3632 /* Draw vertical lines between collections */
3633 bool draw_hierarchy_line;
3634 bool is_object_line;
3635 LISTBASE_FOREACH (TreeElement *, te, lb) {
3636 TreeStoreElem *tselem = TREESTORE(te);
3637 draw_hierarchy_line = false;
3638 is_object_line = false;
3639 *starty -= UI_UNIT_Y;
3640 short color_tag = COLLECTION_COLOR_NONE;
3641
3642 /* Only draw hierarchy lines for expanded collections and objects with children. */
3643 if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
3644 if (tselem->type == TSE_LAYER_COLLECTION) {
3645 draw_hierarchy_line = true;
3646
3648 color_tag = collection->color_tag;
3649
3650 y = *starty;
3651 }
3652 else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
3653 if (subtree_contains_object(&te->subtree)) {
3654 draw_hierarchy_line = true;
3655 is_object_line = true;
3656 y = *starty;
3657 }
3658 }
3659 else if (tselem->type == TSE_GREASE_PENCIL_NODE) {
3662 if (node.is_group() && node.as_group().num_direct_nodes() > 0) {
3663 draw_hierarchy_line = true;
3664 y = *starty;
3665 }
3666 }
3667
3669 space_outliner,
3670 &te->subtree,
3671 tvc,
3672 startx + UI_UNIT_X,
3673 col,
3674 draw_grayed_out,
3675 starty);
3676 }
3677
3678 if (draw_hierarchy_line) {
3679 const short alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 127 : 255;
3680 uchar line_color[4];
3681 if (color_tag != COLLECTION_COLOR_NONE) {
3682 copy_v4_v4_uchar(line_color, btheme->collection_color[color_tag].color);
3683 }
3684 else {
3685 copy_v4_v4_uchar(line_color, col);
3686 }
3687
3688 line_color[3] = alpha_fac;
3689 immUniformColor4ubv(line_color);
3690 outliner_draw_hierarchy_line(pos, startx, y, *starty, is_object_line);
3691 }
3692 }
3693}
3694
3696 ListBase *lb,
3697 const TreeViewContext &tvc,
3698 int startx,
3699 int *starty)
3700{
3702 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3703 uchar col[4];
3704
3706
3707 float viewport_size[4];
3708 GPU_viewport_size_get_f(viewport_size);
3709 immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
3710 immUniform1i("colors_len", 0); /* "simple" mode */
3711 immUniform1f("dash_width", 8.0f);
3713 col[3] = 255;
3714
3715 GPU_line_width(1.0f);
3718 pos, space_outliner, lb, tvc, startx, col, false, starty);
3720
3722}
3723
3725 SpaceOutliner *space_outliner,
3726 ListBase *lb,
3727 int *starty)
3728{
3729 LISTBASE_FOREACH (TreeElement *, te, lb) {
3730 TreeStoreElem *tselem = TREESTORE(te);
3731
3732 /* Selection status. */
3733 if (TSELEM_OPEN(tselem, space_outliner)) {
3734 if (tselem->type == TSE_RNA_STRUCT) {
3737 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3739 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3740 immRectf(pos, 0, *starty + 1, int(region->v2d.cur.xmax), *starty + UI_UNIT_Y - 1);
3742 }
3743 }
3744
3745 *starty -= UI_UNIT_Y;
3746 if (TSELEM_OPEN(tselem, space_outliner)) {
3747 outliner_draw_struct_marks(region, space_outliner, &te->subtree, starty);
3748 if (tselem->type == TSE_RNA_STRUCT) {
3751 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3753 immThemeColorShadeAlpha(TH_BACK, -15, -200);
3754
3756 immVertex2f(pos, 0, float(*starty) + UI_UNIT_Y);
3757 immVertex2f(pos, region->v2d.cur.xmax, float(*starty) + UI_UNIT_Y);
3758 immEnd();
3759
3761 }
3762 }
3763 }
3764}
3765
3766static void outliner_draw_highlights(const ARegion *region,
3767 const SpaceOutliner *space_outliner,
3768 const float col_selection[4],
3769 const float col_active[4],
3770 const float col_highlight[4],
3771 const float col_searchmatch[4],
3772 int /* start_x */,
3773 int *io_start_y)
3774{
3775 const bool is_searching = (SEARCHING_OUTLINER(space_outliner) ||
3776 (space_outliner->outlinevis == SO_DATA_API &&
3777 space_outliner->search_string[0] != 0));
3778
3779 tree_iterator::all_open(*space_outliner, [&](const TreeElement *te) {
3780 const TreeStoreElem *tselem = TREESTORE(te);
3781 const int start_y = *io_start_y;
3782
3783 const float ufac = UI_UNIT_X / 20.0f;
3784 const float radius = UI_UNIT_Y / 8.0f;
3785 const int padding_x = 3 * UI_SCALE_FAC;
3786 rctf rect{};
3787 BLI_rctf_init(&rect,
3788 padding_x,
3789 int(region->v2d.cur.xmax) - padding_x,
3790 start_y + ufac,
3791 start_y + UI_UNIT_Y - ufac);
3793
3794 /* Selection status. */
3795 if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
3796 UI_draw_roundbox_4fv(&rect, true, radius, col_active);
3797
3798 float col_active_outline[4];
3799 UI_GetThemeColorShade4fv(TH_SELECT_ACTIVE, 40, col_active_outline);
3800 UI_draw_roundbox_4fv(&rect, false, radius, col_active_outline);
3801 }
3802 else if (tselem->flag & TSE_SELECTED) {
3803 UI_draw_roundbox_4fv(&rect, true, radius, col_selection);
3804 }
3805
3806 /* Highlights. */
3807 if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
3808 if (tselem->flag & TSE_DRAG_ANY) {
3809 /* Drag and drop highlight. */
3810 float col_outline[4];
3811 UI_GetThemeColorBlend4f(TH_TEXT, TH_BACK, 0.4f, col_outline);
3812
3813 if (tselem->flag & TSE_DRAG_BEFORE) {
3814 rect.ymax += (1.0f * UI_SCALE_FAC) + (1.0f * U.pixelsize);
3815 rect.ymin = rect.ymax - (2.0f * U.pixelsize);
3816 UI_draw_roundbox_4fv(&rect, true, 0.0f, col_outline);
3817 }
3818 else if (tselem->flag & TSE_DRAG_AFTER) {
3819 rect.ymin -= (1.0f * UI_SCALE_FAC) + (1.0f * U.pixelsize);
3820 rect.ymax = rect.ymin + (2.0f * U.pixelsize);
3821 UI_draw_roundbox_4fv(&rect, true, 0.0f, col_outline);
3822 }
3823 else {
3824 float col_bg[4];
3825 UI_GetThemeColorShade4fv(TH_BACK, 40, col_bg);
3826 UI_draw_roundbox_4fv_ex(&rect, col_bg, nullptr, 1.0f, col_outline, U.pixelsize, radius);
3827 }
3828 }
3829 else {
3830 if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
3831 /* Search match highlights. We don't expand items when searching in the data-blocks,
3832 * but we still want to highlight any filter matches. */
3833 UI_draw_roundbox_4fv(&rect, true, radius, col_searchmatch);
3834 }
3835 else if (tselem->flag & TSE_HIGHLIGHTED) {
3836 /* Mouse hover highlight. */
3837 UI_draw_roundbox_4fv(&rect, true, radius, col_highlight);
3838 }
3839 }
3840 }
3841
3842 *io_start_y -= UI_UNIT_Y;
3843 });
3844}
3845
3847 SpaceOutliner *space_outliner,
3848 int startx,
3849 int *starty)
3850{
3851 const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
3852 float col_selection[4], col_active[4], col_searchmatch[4];
3853
3855 col_selection[3] = 1.0f; /* No alpha. */
3857 col_active[3] = 1.0f; /* No alpha. */
3858 UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
3859 col_searchmatch[3] = 0.5f;
3860
3863 space_outliner,
3864 col_selection,
3865 col_active,
3866 col_highlight,
3867 col_searchmatch,
3868 startx,
3869 starty);
3871}
3872
3873static void outliner_draw_tree(uiBlock *block,
3874 const TreeViewContext &tvc,
3875 ARegion *region,
3876 SpaceOutliner *space_outliner,
3877 const float right_column_width,
3878 const bool use_mode_column,
3879 const bool use_warning_column,
3880 TreeElement **te_edit)
3881{
3882 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
3883
3884 short columns_offset = use_mode_column ? UI_UNIT_X : 0;
3885
3886 /* Move the tree a unit left in view layer mode */
3887 if ((space_outliner->outlinevis == SO_VIEW_LAYER) &&
3888 !(space_outliner->filter & SO_FILTER_NO_COLLECTION) &&
3889 (space_outliner->filter & SO_FILTER_NO_VIEW_LAYERS))
3890 {
3891 columns_offset -= UI_UNIT_X;
3892 }
3893
3894 if (use_warning_column) {
3895 columns_offset += UI_UNIT_X;
3896 }
3897
3898 GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
3899
3900 if (space_outliner->outlinevis == SO_DATA_API) {
3901 /* struct marks */
3902 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3903 outliner_draw_struct_marks(region, space_outliner, &space_outliner->tree, &starty);
3904 }
3905
3906 /* Draw highlights before hierarchy. */
3907 int scissor[4] = {0};
3908 {
3909 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3910 int startx = 0;
3911 outliner_draw_highlights(region, space_outliner, startx, &starty);
3912
3913 /* Set scissor so tree elements or lines can't overlap restriction icons. */
3914 if (right_column_width > 0.0f) {
3915 int mask_x = BLI_rcti_size_x(&region->v2d.mask) - int(right_column_width) + 1;
3916 CLAMP_MIN(mask_x, 0);
3917
3918 GPU_scissor_get(scissor);
3919 GPU_scissor(0, 0, mask_x, region->winy);
3920 }
3921 }
3922
3923 /* Draw hierarchy lines for collections and object children. */
3924 {
3925 int starty = int(region->v2d.tot.ymax) - OL_Y_OFFSET;
3926 int startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
3927 outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, tvc, startx, &starty);
3928 }
3929
3930 /* Items themselves. */
3931 {
3932 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y - OL_Y_OFFSET;
3933 int startx = columns_offset;
3934 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
3936 fstyle,
3937 tvc,
3938 region,
3939 space_outliner,
3940 te,
3941 (te->flag & TE_DRAGGING) != 0,
3942 startx,
3943 &starty,
3944 right_column_width,
3945 te_edit);
3946 }
3947
3948 if (right_column_width > 0.0f) {
3949 /* Reset scissor. */
3950 GPU_scissor(UNPACK4(scissor));
3951 }
3952 }
3953}
3954
3955static void outliner_back(ARegion *region)
3956{
3957 int ystart;
3958
3959 ystart = int(region->v2d.tot.ymax);
3960 ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
3961
3963 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
3964
3966
3967 float col_alternating[4];
3968 UI_GetThemeColor4fv(TH_ROW_ALTERNATE, col_alternating);
3970
3971 const float x1 = 0.0f, x2 = region->v2d.cur.xmax;
3972 float y1 = ystart, y2;
3973 int tot = int(floor(ystart - region->v2d.cur.ymin + 2 * UI_UNIT_Y)) / (2 * UI_UNIT_Y);
3974
3975 if (tot > 0) {
3976 immBegin(GPU_PRIM_TRIS, 6 * tot);
3977 while (tot--) {
3978 y1 -= 2 * UI_UNIT_Y;
3979 y2 = y1 + UI_UNIT_Y;
3980 immVertex2f(pos, x1, y1);
3981 immVertex2f(pos, x2, y1);
3982 immVertex2f(pos, x2, y2);
3983
3984 immVertex2f(pos, x1, y1);
3985 immVertex2f(pos, x2, y2);
3986 immVertex2f(pos, x1, y2);
3987 }
3988 immEnd();
3989 }
3991}
3992
3993static int outliner_data_api_buttons_start_x(int max_tree_width)
3994{
3995 return max_ii(OL_RNA_COLX, max_tree_width + OL_RNA_COL_SPACEX);
3996}
3997
3998static int outliner_width(SpaceOutliner *space_outliner,
3999 int max_tree_width,
4000 float right_column_width)
4001{
4002 if (space_outliner->outlinevis == SO_DATA_API) {
4003 return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX +
4004 10 * UI_SCALE_FAC;
4005 }
4006 return max_tree_width + right_column_width;
4007}
4008
4010 SpaceOutliner *space_outliner,
4011 int tree_width,
4012 int tree_height,
4013 float right_column_width)
4014{
4015 int sizex = outliner_width(space_outliner, tree_width, right_column_width);
4016 int sizey = tree_height;
4017
4018 /* Extend size to allow for horizontal scroll-bar and extra offset. */
4019 sizey += V2D_SCROLL_HEIGHT + OL_Y_OFFSET;
4020
4021 UI_view2d_totRect_set(&region->v2d, sizex, sizey);
4022}
4023
4025
4026/* -------------------------------------------------------------------- */
4031
4032void draw_outliner(const bContext *C, bool do_rebuild)
4033{
4034 Main *mainvar = CTX_data_main(C);
4035 WorkSpace *workspace = CTX_wm_workspace(C);
4036 ARegion *region = CTX_wm_region(C);
4037 View2D *v2d = &region->v2d;
4038 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
4039 uiBlock *block;
4040 TreeElement *te_edit = nullptr;
4041
4042 TreeViewContext tvc;
4044
4045 /* FIXME(@ideasman42): There is an order of initialization problem here between
4046 * `v2d->cur` & `v2d->tot` where this function reads from `v2d->cur` for the scroll position
4047 * but may reset the scroll position *without* drawing into the clamped position.
4048 *
4049 * The `on_scroll` argument is used for an optional second draw pass.
4050 *
4051 * See `USE_OUTLINER_DRAW_CLAMPS_SCROLL_HACK` & #128346 for a full description. */
4052
4053 if (do_rebuild) {
4055 mainvar, workspace, tvc.scene, tvc.view_layer, space_outliner, region); /* Always. */
4056
4057 /* If global sync select is dirty, flag other outliners. */
4060 }
4061
4062 /* Sync selection state from view layer. */
4063 if (space_outliner->flag & SO_SYNC_SELECT) {
4064 if (!ELEM(space_outliner->outlinevis,
4069 {
4070 outliner_sync_selection(C, tvc, space_outliner);
4071 }
4072 }
4073 }
4074
4075 /* Force display to pixel coords. */
4077 /* Set matrix for 2D-view controls. */
4079
4080 /* Only show mode column in View Layers and Scenes view. */
4081 const bool use_mode_column = outliner_shows_mode_column(*space_outliner);
4082 const bool use_warning_column = outliner_has_element_warnings(*space_outliner);
4083
4084 /* Draw outliner stuff (background, hierarchy lines and names). */
4085 const float right_column_width = outliner_right_columns_width(space_outliner);
4086 outliner_back(region);
4087 block = UI_block_begin(C, region, __func__, ui::EmbossType::Emboss);
4088 outliner_draw_tree(block,
4089 tvc,
4090 region,
4091 space_outliner,
4092 right_column_width,
4093 use_mode_column,
4094 use_warning_column,
4095 &te_edit);
4096
4097 /* Compute outliner dimensions after it has been drawn. */
4098 int tree_width, tree_height;
4099 outliner_tree_dimensions(space_outliner, &tree_width, &tree_height);
4100
4101 /* Default to no emboss for outliner UI. */
4103
4104 if (space_outliner->outlinevis == SO_DATA_API) {
4105 int buttons_start_x = outliner_data_api_buttons_start_x(tree_width);
4106 /* draw rna buttons */
4107 outliner_draw_separator(region, buttons_start_x);
4108 outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
4109
4111 outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x);
4113 }
4114 else if (ELEM(space_outliner->outlinevis, SO_ID_ORPHANS, SO_LIBRARIES)) {
4115 outliner_draw_userbuts(block, region, space_outliner);
4116 }
4117 else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
4118 const int x = region->v2d.cur.xmax - right_column_width;
4119 outliner_draw_separator(region, x);
4123 outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x);
4125 }
4126 else if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_HIERARCHIES) {
4128 mainvar, block, region, space_outliner, &space_outliner->tree, x);
4129 }
4130 }
4131 else if (right_column_width > 0.0f) {
4132 /* draw restriction columns */
4133 RestrictPropertiesActive props_active;
4134 memset(&props_active, 1, sizeof(RestrictPropertiesActive));
4136 tvc.scene,
4137 tvc.view_layer,
4138 region,
4139 space_outliner,
4140 &space_outliner->tree,
4141 props_active);
4142 }
4143
4144 /* Draw mode icons */
4145 if (use_mode_column) {
4146 outliner_draw_mode_column(block, tvc, space_outliner);
4147 }
4148
4149 /* Draw warning icons */
4150 if (use_warning_column) {
4151 outliner_draw_warning_column(block, space_outliner, use_mode_column);
4152 }
4153
4155
4156 /* Draw edit buttons if necessary. */
4157 if (te_edit) {
4158 outliner_buttons(C, block, region, right_column_width, te_edit);
4159 }
4160
4161 UI_block_end(C, block);
4162 UI_block_draw(C, block);
4163
4164 /* Update total viewable region. */
4166 region, space_outliner, tree_width, tree_height, right_column_width);
4167}
4168
4170
4171} // namespace blender::ed::outliner
4172
4177
4179{
4180 return !((space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) &&
4182}
Functions to deal with Armatures.
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.
Blender kernel action and pose functionality.
bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
WorkSpace * CTX_wm_workspace(const bContext *C)
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:752
void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active)
Low-level operations for grease pencil.
int BKE_idtype_idcode_to_index(short idcode)
Definition idtype.cc:228
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:358
void id_us_min(ID *id)
Definition lib_id.cc:366
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:229
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
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:538
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2384
#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:360
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:1294
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
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 CTX_N_(context, msgid)
#define TIP_(msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_TAG_EXTRAUSER
Definition DNA_ID.h:878
@ ID_TAG_MISSING
Definition DNA_ID.h:867
#define ID_FAKE_USERS(id)
Definition DNA_ID.h:655
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1104
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define INDEX_ID_MAX
Definition DNA_ID.h:1360
@ INDEX_ID_GR
Definition DNA_ID.h:1340
@ INDEX_ID_OB
Definition DNA_ID.h:1339
@ INDEX_ID_GP
Definition DNA_ID.h:1336
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:363
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:769
@ LIBRARY_FLAG_IS_ARCHIVE
Definition DNA_ID.h:593
@ ID_CA
@ ID_AR
@ ID_MC
@ ID_LI
@ ID_TE
@ ID_IM
@ ID_VO
@ ID_WS
@ ID_NT
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SO
@ ID_SCE
@ ID_LS
@ ID_MSK
@ ID_CV
@ ID_PAL
@ ID_BR
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_SCR
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_VF
@ ID_ME
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
#define ID_NLA
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_UNSELECTABLE
@ BONE_HIDDEN_A
@ BONE_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_GEOMETRY_ATTRIBUTE
@ 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
@ LAYER_COLLECTION_EXCLUDE
@ BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT
@ LAYER_COLLECTION_VISIBLE_VIEW_LAYER
@ VIEW_LAYER_RENDER
@ 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_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)
@ OB_DUPLICOLLECTION
@ 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
@ TSE_DRAG_AFTER
@ TSE_SELECTED
@ TSE_HIGHLIGHTED_ICON
@ TSE_HIGHLIGHTED
@ TSE_SEARCHMATCH
@ TSE_DRAG_BEFORE
@ TSE_DRAG_ANY
@ TSE_ACTIVE
@ TSE_TEXTBUT
#define BASE_SELECTED(v3d, base)
@ SCE_OBJECT_MODE_LOCK
@ 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_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:28
int ED_file_extension_icon(const char *path)
Definition filelist.cc:1869
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:98
void immUniformColor4ubv(const unsigned char rgba[4])
void immEnd()
void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
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 immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat()
void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
void immBegin(GPUPrimType, uint vertex_len)
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
void GPU_line_width(float width)
Definition gpu_state.cc:166
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
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
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
PropertyType
Definition RNA_types.hh:161
@ PROP_ENUM
Definition RNA_types.hh:166
@ PROP_POINTER
Definition RNA_types.hh:167
#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_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
uiBut * uiDefIconButBitI(uiBlock *block, ButType 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_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
@ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
@ UI_BUT_DRAG_LOCK
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
uiBut * uiDefIconBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_draw_roundbox_4fv_ex(const rctf *rect, const float inner1[4], const float inner2[4], float shade_dir, const float outline[4], float outline_width, float rad)
std::optional< int64_t > UI_but_context_int_get(const uiBut *but, blender::StringRef name)
uiBut * uiDefIconButBitS(uiBlock *block, ButType 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)
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)
uiBut * uiDefIconButO(uiBlock *block, ButType type, blender::StringRefNull opname, blender::wm::OpCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
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 * uiDefIconButR_prop(uiBlock *block, ButType 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_func_rename_set(uiBut *but, uiButHandleRenameFunc func, void *arg1)
void UI_block_draw(const bContext *C, uiBlock *block)
@ UI_CNR_ALL
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, blender::StringRef name, const PointerRNA *ptr)
void UI_but_icon_indicator_set(uiBut *but, const char *string)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBut *but)
void UI_but_label_alpha_factor_set(uiBut *but, float alpha_factor)
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_BUT_ICON_REVERSE
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)
uiBut * uiDefBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_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)
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_GetThemeColorBlend4f(int colorid1, int colorid2, float fac, float r_col[4])
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:395
@ KM_CTRL
Definition WM_types.hh:279
@ KM_SHIFT
Definition WM_types.hh:278
#define ND_DATA
Definition WM_types.hh:509
#define ND_RENDER_OPTIONS
Definition WM_types.hh:435
#define NC_ANIMATION
Definition WM_types.hh:388
#define NC_SCENE
Definition WM_types.hh:378
#define ND_MODIFIER
Definition WM_types.hh:462
#define ND_POSE
Definition WM_types.hh:458
#define NA_EDITED
Definition WM_types.hh:584
#define NC_MATERIAL
Definition WM_types.hh:380
#define NC_IMAGE
Definition WM_types.hh:384
#define NC_GPENCIL
Definition WM_types.hh:399
#define NC_TEXTURE
Definition WM_types.hh:381
#define ND_BONE_COLLECTION
Definition WM_types.hh:474
#define NA_RENAME
Definition WM_types.hh:588
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_ANIMCHAN
Definition WM_types.hh:496
#define NC_SPACE
Definition WM_types.hh:392
#define NA_SELECTED
Definition WM_types.hh:589
#define ND_SPACE_OUTLINER
Definition WM_types.hh:527
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)
#define GS(x)
uint pos
uint col
#define active
#define select(A, B, C)
#define floor
format
void pose_bone_descendent_iterator(bPose &pose, bPoseChannel &pose_bone, FunctionRef< void(bPoseChannel &child_bone)> callback)
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 void outliner_draw_highlights(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, int *io_start_y)
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)
static bool outliner_but_identity_cmp_context_id_fn(const uiBut *a, const uiBut *b)
static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *poin2)
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)
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 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)
void outliner_build_tree(Main *mainvar, WorkSpace *workspace, Scene *scene, ViewLayer *view_layer, SpaceOutliner *space_outliner, ARegion *region)
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)
const char * name
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
CollectionRuntimeHandle * runtime
short ob_type
char name[64]
unsigned int flag
Definition DNA_ID.h:348
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
int us
Definition DNA_ID.h:443
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
short flag
Definition DNA_ID.h:438
ListBase layer_collections
struct Collection * collection
char filepath[1024]
Definition DNA_ID.h:552
short type
void * first
ListBase objects
Definition BKE_main.hh:280
short transflag
struct Collection * instance_collection
struct bPose * pose
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:774
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:4238
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
uint8_t flag
Definition wm_window.cc:145