Blender  V3.3
tree_display_view_layer.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <iostream>
8 
9 #include "DNA_collection_types.h"
10 #include "DNA_scene_types.h"
11 #include "DNA_space_types.h"
12 
13 #include "BKE_layer.h"
14 
15 #include "BLI_listbase.h"
16 #include "BLI_listbase_wrapper.hh"
17 #include "BLI_map.hh"
18 #include "BLI_vector.hh"
19 
20 #include "BLT_translation.h"
21 
22 #include "../outliner_intern.hh"
23 #include "common.hh"
24 #include "tree_display.hh"
25 #include "tree_element.hh"
26 
27 namespace blender::ed::outliner {
28 
29 template<typename T> using List = ListBaseWrapper<T>;
30 
34 
35  SpaceOutliner &outliner_;
36  ObjectTreeElementsMap object_tree_elements_map_;
37 
38  public:
41 
42  void operator()(TreeElement &collection_tree_elem);
43 
44  private:
45  void object_tree_elements_lookup_create_recursive(TreeElement *te_parent);
46  void make_object_parent_hierarchy_collections();
47 };
48 
49 /* -------------------------------------------------------------------- */
54  : AbstractTreeDisplay(space_outliner)
55 {
56 }
57 
59 {
60  return true;
61 }
62 
64 {
65  ListBase tree = {nullptr};
66  Scene *scene = source_data.scene;
67  show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
68 
69  for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene->view_layers)) {
70  view_layer_ = view_layer;
71 
73  if (view_layer != source_data.view_layer) {
74  continue;
75  }
76 
77  add_view_layer(*scene, tree, (TreeElement *)nullptr);
78  }
79  else {
80  TreeElement &te_view_layer = *outliner_add_element(
81  &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0);
82  TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED;
83  te_view_layer.name = view_layer->name;
84  te_view_layer.directdata = view_layer;
85 
86  add_view_layer(*scene, te_view_layer.subtree, &te_view_layer);
87  }
88  }
89 
90  return tree;
91 }
92 
93 void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent)
94 {
95  const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
96 
98  /* Show objects in the view layer. */
99  for (Base *base : List<Base>(view_layer_->object_bases)) {
100  TreeElement *te_object = outliner_add_element(
101  &space_outliner_, &tree, base->object, parent, TSE_SOME_ID, 0);
102  te_object->directdata = base;
103  }
104 
105  if (show_children) {
107  }
108  }
109  else {
110  /* Show collections in the view layer. */
113  ten.name = IFACE_("Scene Collection");
114  TREESTORE(&ten)->flag &= ~TSE_CLOSED;
115 
116  /* First layer collection is for master collection, don't show it. */
117  LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
118  if (lc == nullptr) {
119  return;
120  }
121 
122  add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten);
123  if (show_objects_) {
124  add_layer_collection_objects(ten.subtree, *lc, ten);
125  }
126  if (show_children) {
127  add_layer_collection_objects_children(ten);
128  }
129  }
130 }
131 
132 void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree,
133  ListBase &layer_collections,
134  TreeElement &parent_ten)
135 {
136  for (LayerCollection *lc : List<LayerCollection>(layer_collections)) {
137  const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
138  TreeElement *ten;
139 
140  if (exclude && ((space_outliner_.show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) {
141  ten = &parent_ten;
142  }
143  else {
144  ID *id = &lc->collection->id;
145  ten = outliner_add_element(
146  &space_outliner_, &tree, id, &parent_ten, TSE_LAYER_COLLECTION, 0);
147 
148  ten->name = id->name + 2;
149  ten->directdata = lc;
150 
151  /* Open by default, except linked collections, which may contain many elements. */
152  TreeStoreElem *tselem = TREESTORE(ten);
153  if (!(tselem->used || ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
154  tselem->flag &= ~TSE_CLOSED;
155  }
156  }
157 
158  add_layer_collections_recursive(ten->subtree, lc->layer_collections, *ten);
159  if (!exclude && show_objects_) {
160  add_layer_collection_objects(ten->subtree, *lc, *ten);
161  }
162  }
163 }
164 
165 void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
166  LayerCollection &lc,
167  TreeElement &ten)
168 {
169  for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) {
170  Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
171  TreeElement *te_object = outliner_add_element(
172  &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0);
173  te_object->directdata = base;
174  }
175 }
176 
177 void TreeDisplayViewLayer::add_layer_collection_objects_children(TreeElement &collection_tree_elem)
178 {
179  /* Call helper to add children. */
180  ObjectsChildrenBuilder child_builder{space_outliner_};
181  child_builder(collection_tree_elem);
182 }
183 
186 /* -------------------------------------------------------------------- */
195 {
196 }
197 
199 {
200  object_tree_elements_lookup_create_recursive(&collection_tree_elem);
201  make_object_parent_hierarchy_collections();
202 }
203 
207 void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeElement *te_parent)
208 {
209  for (TreeElement *te : List<TreeElement>(te_parent->subtree)) {
210  TreeStoreElem *tselem = TREESTORE(te);
211 
212  if (tselem->type == TSE_LAYER_COLLECTION) {
213  object_tree_elements_lookup_create_recursive(te);
214  continue;
215  }
216 
217  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
218  Object *ob = (Object *)tselem->id;
219  /* Lookup children or add new, empty children vector. */
220  Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
221 
222  tree_elements.append(te);
223  object_tree_elements_lookup_create_recursive(te);
224  }
225  }
226 }
227 
232 void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
233 {
234  for (ObjectTreeElementsMap::MutableItem item : object_tree_elements_map_.items()) {
235  Object *child = item.key;
236 
237  if (child->parent == nullptr) {
238  continue;
239  }
240 
241  Vector<TreeElement *> &child_ob_tree_elements = item.value;
242  Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
243  child->parent);
244  if (parent_ob_tree_elements == nullptr) {
245  continue;
246  }
247 
248  for (TreeElement *parent_ob_tree_element : *parent_ob_tree_elements) {
249  TreeElement *parent_ob_collection_tree_element = nullptr;
250  bool found = false;
251 
252  /* We always want to remove the child from the direct collection its parent is nested under.
253  * This is particularly important when dealing with multi-level nesting (grandchildren). */
254  parent_ob_collection_tree_element = parent_ob_tree_element->parent;
255  while (!ELEM(TREESTORE(parent_ob_collection_tree_element)->type,
258  parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
259  }
260 
261  for (TreeElement *child_ob_tree_element : child_ob_tree_elements) {
262  if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
263  /* Move from the collection subtree into the parent object subtree. */
264  BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element);
265  BLI_addtail(&parent_ob_tree_element->subtree, child_ob_tree_element);
266  child_ob_tree_element->parent = parent_ob_tree_element;
267  found = true;
268  break;
269  }
270  }
271 
272  if (!found) {
273  /* We add the child in the tree even if it is not in the collection.
274  * We don't expand its sub-tree though, to make it less prominent. */
275  TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
276  &parent_ob_tree_element->subtree,
277  child,
278  parent_ob_tree_element,
279  TSE_SOME_ID,
280  0,
281  false);
282  child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
283  child_ob_tree_elements.append(child_ob_tree_element);
284  }
285  }
286  }
287 }
288 
291 } // namespace blender::ed::outliner
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
#define ELEM(...)
#define IFACE_(msgid)
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
@ ID_OB
Definition: DNA_ID_enums.h:47
Object groups, one object can be in many groups at once.
@ LAYER_COLLECTION_EXCLUDE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_LAYER_COLLECTION
@ TSE_SOME_ID
@ TSE_R_LAYER
@ TSE_CLOSED
@ SO_RESTRICT_ENABLE
@ SO_FILTER_NO_CHILDREN
@ SO_FILTER_NO_OBJECT
@ SO_FILTER_NO_VIEW_LAYERS
@ SO_FILTER_NO_COLLECTION
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Value & lookup_or_add(const Key &key, const Value &value)
Definition: BLI_map.hh:530
void append(const T &value)
Definition: BLI_vector.hh:433
Base Class For Tree-Displays.
Definition: tree_display.hh:62
void operator()(TreeElement &collection_tree_elem)
ListBase buildTree(const TreeSourceData &source_data) override
TreeDisplayViewLayer(SpaceOutliner &space_outliner)
void outliner_make_object_parent_hierarchy(ListBase *lb)
Definition: common.cc:37
Scene scene
void * tree
TreeElement * outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, TreeElement *parent, short type, short index, const bool expand)
ListBaseWrapper< T > List
@ TE_CHILD_NOT_IN_COLLECTION
#define TREESTORE(a)
struct Object * object
Definition: DNA_ID.h:368
ListBase layer_collections
struct Collection * collection
void * first
Definition: DNA_listBase.h:31
struct Object * parent
ListBase view_layers
struct TreeElement * parent
ListBase subtree
const char * name
ListBase layer_collections
ListBase object_bases
The data to build the tree from.
Definition: tree_display.hh:43
Establish and manage Outliner trees for different display modes.