Blender V4.5
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 for (TreeElement *ten : List<TreeElement>(tree)) {
62 if (ten == tree.first) {
63 /* First item is main, skip. */
64 continue;
65 }
66
67 TreeStoreElem *tselem = TREESTORE(ten);
68 Library *lib = (Library *)tselem->id;
69 BLI_assert(!lib || (GS(lib->id.name) == ID_LI));
70 if (!lib || !lib->runtime->parent) {
71 continue;
72 }
73
74 TreeElement *parent = (TreeElement *)lib->runtime->parent->id.newid;
75
76 if (tselem->id->tag & ID_TAG_INDIRECT) {
77 /* Only remove from 'first level' if lib is not also directly used. */
78 BLI_remlink(&tree, ten);
79 BLI_addtail(&parent->subtree, ten);
80 ten->parent = parent;
81 }
82 else {
83 /* Else, make a new copy of the libtree for our parent. */
84 TreeElement *dupten = add_library_contents(*source_data.bmain, parent->subtree, lib);
85 if (dupten) {
86 dupten->parent = parent;
87 }
88 }
89 }
90 /* restore newid pointers */
91 for (ID *library_id : List<ID>(source_data.bmain->libraries)) {
92 library_id->newid = nullptr;
93 }
94
95 return tree;
96}
97
98TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
99{
100 const short filter_id_type = id_filter_get();
101
102 Vector<ListBase *> lbarray;
103 if (filter_id_type) {
105 }
106 else {
107 lbarray.extend(BKE_main_lists_get(mainvar));
108 }
109
110 TreeElement *tenlib = nullptr;
111 for (int a = 0; a < lbarray.size(); a++) {
112 if (!lbarray[a] || !lbarray[a]->first) {
113 continue;
114 }
115
116 ID *id = static_cast<ID *>(lbarray[a]->first);
117 const bool is_library = (GS(id->name) == ID_LI) && (lib != nullptr);
118
119 /* Don't show deprecated types. */
120 if (ID_TYPE_IS_DEPRECATED(GS(id->name))) {
121 continue;
122 }
123
124 /* check if there's data in current lib */
125 for (ID *id_iter : List<ID>(lbarray[a])) {
126 if (id_iter->lib == lib) {
127 id = id_iter;
128 break;
129 }
130 }
131
132 /* We always want to create an entry for libraries, even if/when we have no more IDs from them.
133 * This invalid state is important to show to user as well. */
134 if (id != nullptr || is_library) {
135 if (!tenlib) {
136 /* Create library tree element on demand, depending if there are any data-blocks. */
137 if (lib) {
138 tenlib = add_element(&lb, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_SOME_ID, 0);
139 }
140 else {
141 tenlib = add_element(&lb, nullptr, &mainvar, nullptr, TSE_ID_BASE, 0);
142 tenlib->name = IFACE_("Current File");
143 }
144 }
145
146 /* Create data-block list parent element on demand. */
147 if (id != nullptr) {
148 TreeElement *ten;
149
150 if (filter_id_type) {
151 ten = tenlib;
152 }
153 else {
154 ten = add_element(
155 &tenlib->subtree, reinterpret_cast<ID *>(lib), nullptr, nullptr, TSE_ID_BASE, a);
156 ten->directdata = lbarray[a];
157 ten->name = outliner_idcode_to_plural(GS(id->name));
158 }
159
160 for (ID *id : List<ID>(lbarray[a])) {
161 if (library_id_filter_poll(lib, id)) {
162 add_element(&ten->subtree, id, nullptr, ten, TSE_SOME_ID, 0);
163 }
164 }
165 }
166 }
167 }
168
169 return tenlib;
170}
171
172short TreeDisplayLibraries::id_filter_get() const
173{
174 if (space_outliner_.filter & SO_FILTER_ID_TYPE) {
175 return space_outliner_.filter_id_type;
176 }
177 return 0;
178}
179
180bool TreeDisplayLibraries::library_id_filter_poll(const Library *lib, ID *id) const
181{
182 if (id->lib != lib) {
183 return false;
184 }
185
186 if (id_filter_get() == ID_GR) {
187 /* Don't show child collections of non-scene master collection,
188 * they are already shown as children. */
189 Collection *collection = (Collection *)id;
190 bool has_non_scene_parent = false;
191
192 for (CollectionParent *cparent : List<CollectionParent>(collection->runtime.parents)) {
193 if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
194 has_non_scene_parent = true;
195 }
196 }
197
198 if (has_non_scene_parent) {
199 return false;
200 }
201 }
202
203 return true;
204}
205
206} // namespace blender::ed::outliner
MainListsArray BKE_main_lists_get(Main &bmain)
Definition main.cc:969
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:882
#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
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_LI
@ ID_GR
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
struct Collection Collection
@ TSE_CLOSED
@ TSE_ID_BASE
@ TSE_SOME_ID
@ 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 ID_TYPE_IS_DEPRECATED(id_type)
#define GS(a)
const char * outliner_idcode_to_plural(short idcode)
Definition common.cc:31
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
#define TREESTORE(a)
Collection_Runtime runtime
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct Library * lib
Definition DNA_ID.h:410
char name[66]
Definition DNA_ID.h:415
The data to build the tree from.
Establish and manage Outliner trees for different display modes.
static DynamicLibrary lib