Blender V4.3
tree_display_libraries.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_listbase.h"
11
12#include "BKE_collection.hh"
13#include "BKE_main.hh"
14
16#include "DNA_space_types.h"
17
18#include "BLT_translation.hh"
19
20#include "../outliner_intern.hh"
21#include "common.hh"
22#include "tree_display.hh"
23
24namespace blender::ed::outliner {
25
26template<typename T> using List = ListBaseWrapper<T>;
27
32
34{
35 ListBase tree = {nullptr};
36
37 {
38 /* current file first - mainvar provides tselem with unique pointer - not used */
39 TreeElement *ten = add_library_contents(*source_data.bmain, tree, nullptr);
40 TreeStoreElem *tselem;
41
42 if (ten) {
43 tselem = TREESTORE(ten);
44 if (!tselem->used) {
45 tselem->flag &= ~TSE_CLOSED;
46 }
47 }
48 }
49
50 for (ID *id : List<ID>(source_data.bmain->libraries)) {
51 Library *lib = reinterpret_cast<Library *>(id);
52 TreeElement *ten = add_library_contents(*source_data.bmain, tree, lib);
53 /* Null-check matters, due to filtering there may not be a new element. */
54 if (ten) {
55 lib->id.newid = (ID *)ten;
56 }
57 }
58
59 /* make hierarchy */
60 for (TreeElement *ten : List<TreeElement>(tree)) {
61 if (ten == tree.first) {
62 /* First item is main, skip. */
63 continue;
64 }
65
66 TreeStoreElem *tselem = TREESTORE(ten);
67 Library *lib = (Library *)tselem->id;
68 BLI_assert(!lib || (GS(lib->id.name) == ID_LI));
69 if (!lib || !lib->runtime.parent) {
70 continue;
71 }
72
73 TreeElement *parent = (TreeElement *)lib->runtime.parent->id.newid;
74
75 if (tselem->id->tag & ID_TAG_INDIRECT) {
76 /* Only remove from 'first level' if lib is not also directly used. */
77 BLI_remlink(&tree, ten);
78 BLI_addtail(&parent->subtree, ten);
79 ten->parent = parent;
80 }
81 else {
82 /* Else, make a new copy of the libtree for our parent. */
83 TreeElement *dupten = add_library_contents(*source_data.bmain, parent->subtree, lib);
84 if (dupten) {
85 dupten->parent = parent;
86 }
87 }
88 }
89 /* restore newid pointers */
90 for (ID *library_id : List<ID>(source_data.bmain->libraries)) {
91 library_id->newid = nullptr;
92 }
93
94 return tree;
95}
96
97TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
98{
99 const short filter_id_type = id_filter_get();
100
101 ListBase *lbarray[INDEX_ID_MAX];
102 int tot;
103 if (filter_id_type) {
104 lbarray[0] = which_libbase(&mainvar, space_outliner_.filter_id_type);
105 tot = 1;
106 }
107 else {
108 tot = set_listbasepointers(&mainvar, lbarray);
109 }
110
111 TreeElement *tenlib = nullptr;
112 for (int a = 0; a < tot; a++) {
113 if (!lbarray[a] || !lbarray[a]->first) {
114 continue;
115 }
116
117 ID *id = static_cast<ID *>(lbarray[a]->first);
118 const bool is_library = (GS(id->name) == ID_LI) && (lib != nullptr);
119
120 /* Don't show deprecated types. */
121 if (ID_TYPE_IS_DEPRECATED(GS(id->name))) {
122 continue;
123 }
124
125 /* check if there's data in current lib */
126 for (ID *id_iter : List<ID>(lbarray[a])) {
127 if (id_iter->lib == lib) {
128 id = id_iter;
129 break;
130 }
131 }
132
133 /* We always want to create an entry for libraries, even if/when we have no more IDs from them.
134 * This invalid state is important to show to user as well. */
135 if (id != nullptr || is_library) {
136 if (!tenlib) {
137 /* Create library tree element on demand, depending if there are any data-blocks. */
138 if (lib) {
139 tenlib = add_element(&lb, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_SOME_ID, 0);
140 }
141 else {
142 tenlib = add_element(&lb, nullptr, &mainvar, nullptr, TSE_ID_BASE, 0);
143 tenlib->name = IFACE_("Current File");
144 }
145 }
146
147 /* Create data-block list parent element on demand. */
148 if (id != nullptr) {
149 TreeElement *ten;
150
151 if (filter_id_type) {
152 ten = tenlib;
153 }
154 else {
155 ten = add_element(
156 &tenlib->subtree, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_ID_BASE, a);
157 ten->directdata = lbarray[a];
158 ten->name = outliner_idcode_to_plural(GS(id->name));
159 }
160
161 for (ID *id : List<ID>(lbarray[a])) {
162 if (library_id_filter_poll(lib, id)) {
163 add_element(&ten->subtree, id, nullptr, ten, TSE_SOME_ID, 0);
164 }
165 }
166 }
167 }
168 }
169
170 return tenlib;
171}
172
173short TreeDisplayLibraries::id_filter_get() const
174{
177 }
178 return 0;
179}
180
181bool TreeDisplayLibraries::library_id_filter_poll(const Library *lib, ID *id) const
182{
183 if (id->lib != lib) {
184 return false;
185 }
186
187 if (id_filter_get() == ID_GR) {
188 /* Don't show child collections of non-scene master collection,
189 * they are already shown as children. */
190 Collection *collection = (Collection *)id;
191 bool has_non_scene_parent = false;
192
193 for (CollectionParent *cparent : List<CollectionParent>(collection->runtime.parents)) {
194 if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
195 has_non_scene_parent = true;
196 }
197 }
198
199 if (has_non_scene_parent) {
200 return false;
201 }
202 }
203
204 return true;
205}
206
207} // namespace blender::ed::outliner
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:842
int set_listbasepointers(Main *bmain, ListBase *lb[])
Definition main.cc:929
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define IFACE_(msgid)
#define ID_TYPE_IS_DEPRECATED(id_type)
Definition DNA_ID.h:700
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
#define INDEX_ID_MAX
Definition DNA_ID.h:1328
@ ID_LI
@ ID_GR
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
@ TSE_ID_BASE
@ TSE_SOME_ID
@ SO_FILTER_ID_TYPE
Base Class For Tree-Displays.
static TreeElement * add_element(SpaceOutliner *space_outliner, ListBase *lb, ID *owner_id, void *create_data, TreeElement *parent, short type, short index, const bool expand=true)
TreeDisplayLibraries(SpaceOutliner &space_outliner)
ListBase build_tree(const TreeSourceData &source_data) override
GPU_SHADER_INTERFACE_INFO(depth_2d_update_iface, "").smooth(Type fragColor push_constant(Type::VEC2, "extent") .push_constant(Type source_data
KDTree_3d * tree
#define GS(x)
Definition iris.cc:202
const char * outliner_idcode_to_plural(short idcode)
Definition common.cc:31
#define TREESTORE(a)
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
void * first
The data to build the tree from.
Establish and manage Outliner trees for different display modes.
static DynamicLibrary lib