Blender V5.0
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
8
9#include "BLI_listbase.h"
11
12#include "BKE_collection.hh"
13#include "BKE_library.hh"
14#include "BKE_main.hh"
15
17#include "DNA_space_types.h"
18
19#include "BLT_translation.hh"
20
21#include "../outliner_intern.hh"
22#include "common.hh"
23#include "tree_display.hh"
24
25namespace blender::ed::outliner {
26
27template<typename T> using List = ListBaseWrapper<T>;
28
33
35{
36 ListBase tree = {nullptr};
37
38 {
39 /* current file first - mainvar provides tselem with unique pointer - not used */
40 TreeElement *ten = add_library_contents(*source_data.bmain, tree, nullptr);
41 TreeStoreElem *tselem;
42
43 if (ten) {
44 tselem = TREESTORE(ten);
45 if (!tselem->used) {
46 tselem->flag &= ~TSE_CLOSED;
47 }
48 }
49 }
50
51 for (ID *id : List<ID>(source_data.bmain->libraries)) {
52 Library *lib = reinterpret_cast<Library *>(id);
53 TreeElement *ten = add_library_contents(*source_data.bmain, tree, lib);
54 /* Null-check matters, due to filtering there may not be a new element. */
55 if (ten) {
56 lib->id.newid = (ID *)ten;
57 }
58 }
59
60 /* Make hierarchy.
61 *
62 * Note: `List<T>` template is similar to `LISTBASE_FOREACH`, _not_ `LISTBASE_FOREACH_MUTABLE`,
63 * so we need to iterate over an actual copy of the original list here, to avoid missing some
64 * items. */
66 if (ten == tree.first) {
67 /* First item is main, skip. */
68 continue;
69 }
70
71 TreeStoreElem *tselem = TREESTORE(ten);
72 Library *lib = (Library *)tselem->id;
73 BLI_assert(!lib || (GS(lib->id.name) == ID_LI));
74 if (!lib || !(lib->runtime->parent || lib->archive_parent_library)) {
75 continue;
76 }
77
78 /* A library with a non-null `parent` is always strictly indirectly linked. */
79 TreeElement *parent = reinterpret_cast<TreeElement *>(
80 (lib->archive_parent_library ? lib->archive_parent_library : lib->runtime->parent)
81 ->id.newid);
82 BLI_remlink(&tree, ten);
83 BLI_addtail(&parent->subtree, ten);
84 ten->parent = parent;
85 }
86 /* restore newid pointers */
87 for (ID *library_id : List<ID>(source_data.bmain->libraries)) {
88 library_id->newid = nullptr;
89 }
90
91 return tree;
92}
93
94TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
95{
96 const short filter_id_type = id_filter_get();
97
98 Vector<ListBase *> lbarray;
99 if (filter_id_type) {
101 }
102 else {
103 lbarray.extend(BKE_main_lists_get(mainvar));
104 }
105
106 TreeElement *tenlib = nullptr;
107 for (int a = 0; a < lbarray.size(); a++) {
108 if (!lbarray[a] || !lbarray[a]->first) {
109 continue;
110 }
111
112 ID *id = static_cast<ID *>(lbarray[a]->first);
113 const bool is_library = (GS(id->name) == ID_LI) && (lib != nullptr);
114
115 /* Don't show deprecated types. */
116 if (ID_TYPE_IS_DEPRECATED(GS(id->name))) {
117 continue;
118 }
119
120 /* check if there's data in current lib */
121 for (ID *id_iter : List<ID>(lbarray[a])) {
122 if (id_iter->lib == lib) {
123 id = id_iter;
124 break;
125 }
126 }
127
128 /* We always want to create an entry for libraries, even if/when we have no more IDs from them.
129 * This invalid state is important to show to user as well. */
130 if (id != nullptr || is_library) {
131 if (!tenlib) {
132 /* Create library tree element on demand, depending if there are any data-blocks. */
133 if (lib) {
134 tenlib = add_element(&lb, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_SOME_ID, 0);
135 }
136 else {
137 tenlib = add_element(&lb, nullptr, &mainvar, nullptr, TSE_ID_BASE, 0);
138 tenlib->name = IFACE_("Current File");
139 }
140 }
141
142 /* Create data-block list parent element on demand. */
143 if (id != nullptr) {
144 TreeElement *ten;
145
146 if (filter_id_type) {
147 ten = tenlib;
148 }
149 else if (id->lib == lib) {
150 ten = add_element(
151 &tenlib->subtree, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_ID_BASE, a);
152 ten->directdata = lbarray[a];
153 ten->name = outliner_idcode_to_plural(GS(id->name));
154 }
155
156 for (ID *id : List<ID>(lbarray[a])) {
157 if (library_id_filter_poll(lib, id)) {
158 add_element(&ten->subtree, id, nullptr, ten, TSE_SOME_ID, 0);
159 }
160 }
161 }
162 }
163 }
164
165 return tenlib;
166}
167
168short TreeDisplayLibraries::id_filter_get() const
169{
170 if (space_outliner_.filter & SO_FILTER_ID_TYPE) {
171 return space_outliner_.filter_id_type;
172 }
173 return 0;
174}
175
176bool TreeDisplayLibraries::library_id_filter_poll(const Library *lib, ID *id) const
177{
178 if (id->lib != lib) {
179 return false;
180 }
181
182 if (id_filter_get() == ID_GR) {
183 /* Don't show child collections of non-scene master collection,
184 * they are already shown as children. */
185 Collection *collection = (Collection *)id;
186 bool has_non_scene_parent = false;
187
188 for (CollectionParent *cparent : List<CollectionParent>(collection->runtime->parents)) {
189 if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
190 has_non_scene_parent = true;
191 }
192 }
193
194 if (has_non_scene_parent) {
195 return false;
196 }
197 }
198
199 return true;
200}
201
202} // namespace blender::ed::outliner
MainListsArray BKE_main_lists_get(Main &bmain)
Definition main.cc:987
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:902
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
#define IFACE_(msgid)
struct Library Library
struct ID ID
#define ID_TYPE_IS_DEPRECATED(id_type)
Definition DNA_ID.h:749
@ ID_LI
@ ID_GR
Object groups, one object can be in many groups at once.
struct Collection Collection
@ COLLECTION_IS_MASTER
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_CLOSED
@ SO_FILTER_ID_TYPE
int64_t size() const
void append(const T &value)
void extend(Span< T > array)
const T & first() const
AbstractTreeDisplay(SpaceOutliner &space_outliner)
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::float2_t, "extent") .push_constant(Type source_data
KDTree_3d * tree
#define GS(x)
const char * outliner_idcode_to_plural(short idcode)
Definition common.cc:31
Vector< T * > listbase_to_vector(ListBase &list)
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
#define TREESTORE(a)
CollectionRuntimeHandle * runtime
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
The data to build the tree from.
Establish and manage Outliner trees for different display modes.
static DynamicLibrary lib