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