Blender  V2.93
tree_display_view_layer.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <iostream>
22 
23 #include "DNA_collection_types.h"
24 #include "DNA_scene_types.h"
25 
26 #include "BKE_layer.h"
27 
28 #include "BLI_listbase.h"
29 #include "BLI_listbase_wrapper.hh"
30 #include "BLI_map.hh"
31 #include "BLI_vector.hh"
32 
33 #include "BLT_translation.h"
34 
35 #include "../outliner_intern.h"
36 #include "tree_display.hh"
37 
38 namespace blender::ed::outliner {
39 
40 /* Convenience/readability. */
41 template<typename T> using List = ListBaseWrapper<T>;
42 
46 
47  SpaceOutliner &outliner_;
48  ObjectTreeElementsMap object_tree_elements_map_;
49 
50  public:
53 
54  void operator()(TreeElement &collection_tree_elem);
55 
56  private:
57  void object_tree_elements_lookup_create_recursive(TreeElement *te_parent);
58  void make_object_parent_hierarchy_collections();
59 };
60 
61 /* -------------------------------------------------------------------- */
66  : AbstractTreeDisplay(space_outliner)
67 {
68 }
69 
71 {
72  ListBase tree = {nullptr};
73 
74  view_layer_ = source_data.view_layer;
75  show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT);
76 
77  const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0;
78 
80  /* Show objects in the view layer. */
81  for (Base *base : List<Base>(view_layer_->object_bases)) {
82  TreeElement *te_object = outliner_add_element(
83  &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0);
84  te_object->directdata = base;
85  }
86 
87  if (show_children) {
89  }
90  }
91  else {
92  /* Show collections in the view layer. */
94  &space_outliner_, &tree, source_data.scene, nullptr, TSE_VIEW_COLLECTION_BASE, 0);
95  ten.name = IFACE_("Scene Collection");
96  TREESTORE(&ten)->flag &= ~TSE_CLOSED;
97 
98  add_view_layer(ten.subtree, ten);
99  if (show_children) {
100  add_layer_collection_objects_children(ten);
101  }
102  }
103 
104  return tree;
105 }
106 
107 void TreeDisplayViewLayer::add_view_layer(ListBase &tree, TreeElement &parent)
108 {
109  /* First layer collection is for master collection, don't show it. */
110  LayerCollection *lc = static_cast<LayerCollection *>(view_layer_->layer_collections.first);
111  if (lc == nullptr) {
112  return;
113  }
114 
115  add_layer_collections_recursive(tree, lc->layer_collections, parent);
116  if (show_objects_) {
117  add_layer_collection_objects(tree, *lc, parent);
118  }
119 }
120 
121 void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree,
122  ListBase &layer_collections,
123  TreeElement &parent_ten)
124 {
125  for (LayerCollection *lc : List<LayerCollection>(layer_collections)) {
126  const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
127  TreeElement *ten;
128 
129  if (exclude && ((space_outliner_.show_restrict_flags & SO_RESTRICT_ENABLE) == 0)) {
130  ten = &parent_ten;
131  }
132  else {
133  ID *id = &lc->collection->id;
134  ten = outliner_add_element(
135  &space_outliner_, &tree, id, &parent_ten, TSE_LAYER_COLLECTION, 0);
136 
137  ten->name = id->name + 2;
138  ten->directdata = lc;
139 
140  /* Open by default, except linked collections, which may contain many elements. */
141  TreeStoreElem *tselem = TREESTORE(ten);
142  if (!(tselem->used || ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
143  tselem->flag &= ~TSE_CLOSED;
144  }
145  }
146 
147  add_layer_collections_recursive(ten->subtree, lc->layer_collections, *ten);
148  if (!exclude && show_objects_) {
149  add_layer_collection_objects(ten->subtree, *lc, *ten);
150  }
151 
152  const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner_) ||
154 
155  if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY_REAL(&lc->collection->id)) {
158  }
159  }
160 }
161 
162 void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree,
163  LayerCollection &lc,
164  TreeElement &ten)
165 {
166  for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) {
167  Base *base = BKE_view_layer_base_find(view_layer_, cob->ob);
168  TreeElement *te_object = outliner_add_element(
169  &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0);
170  te_object->directdata = base;
171  }
172 }
173 
174 void TreeDisplayViewLayer::add_layer_collection_objects_children(TreeElement &collection_tree_elem)
175 {
176  /* Call helper to add children. */
177  ObjectsChildrenBuilder child_builder{space_outliner_};
178  child_builder(collection_tree_elem);
179 }
180 
183 /* -------------------------------------------------------------------- */
192 {
193 }
194 
196 {
197  object_tree_elements_lookup_create_recursive(&collection_tree_elem);
198  make_object_parent_hierarchy_collections();
199 }
200 
204 void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeElement *te_parent)
205 {
206  for (TreeElement *te : List<TreeElement>(te_parent->subtree)) {
207  TreeStoreElem *tselem = TREESTORE(te);
208 
209  if (tselem->type == TSE_LAYER_COLLECTION) {
210  object_tree_elements_lookup_create_recursive(te);
211  continue;
212  }
213 
214  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
215  Object *ob = (Object *)tselem->id;
216  /* Lookup children or add new, empty children vector. */
217  Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {});
218 
219  tree_elements.append(te);
220  object_tree_elements_lookup_create_recursive(te);
221  }
222  }
223 }
224 
229 void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
230 {
231  for (ObjectTreeElementsMap::MutableItem item : object_tree_elements_map_.items()) {
232  Object *child = item.key;
233 
234  if (child->parent == nullptr) {
235  continue;
236  }
237 
238  Vector<TreeElement *> &child_ob_tree_elements = item.value;
239  Vector<TreeElement *> *parent_ob_tree_elements = object_tree_elements_map_.lookup_ptr(
240  child->parent);
241  if (parent_ob_tree_elements == nullptr) {
242  continue;
243  }
244 
245  for (TreeElement *parent_ob_tree_element : *parent_ob_tree_elements) {
246  TreeElement *parent_ob_collection_tree_element = nullptr;
247  bool found = false;
248 
249  /* We always want to remove the child from the direct collection its parent is nested under.
250  * This is particularly important when dealing with multi-level nesting (grandchildren). */
251  parent_ob_collection_tree_element = parent_ob_tree_element->parent;
252  while (!ELEM(TREESTORE(parent_ob_collection_tree_element)->type,
255  parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
256  }
257 
258  for (TreeElement *child_ob_tree_element : child_ob_tree_elements) {
259  if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
260  /* Move from the collection subtree into the parent object subtree. */
261  BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element);
262  BLI_addtail(&parent_ob_tree_element->subtree, child_ob_tree_element);
263  child_ob_tree_element->parent = parent_ob_tree_element;
264  found = true;
265  break;
266  }
267  }
268 
269  if (!found) {
270  /* We add the child in the tree even if it is not in the collection.
271  * We deliberately clear its sub-tree though, to make it less prominent. */
272  TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
273  &parent_ob_tree_element->subtree,
274  child,
275  parent_ob_tree_element,
276  TSE_SOME_ID,
277  0);
278  outliner_free_tree(&child_ob_tree_element->subtree);
279  child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
280  child_ob_tree_elements.append(child_ob_tree_element);
281  }
282  }
283  }
284 }
285 
288 } // namespace blender::ed::outliner
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
#define ELEM(...)
#define IFACE_(msgid)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition: DNA_ID.h:438
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:426
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:445
@ ID_OB
Definition: DNA_ID_enums.h:59
Object groups, one object can be in many groups at once.
@ LAYER_COLLECTION_EXCLUDE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_LIBRARY_OVERRIDE_BASE
@ TSE_LAYER_COLLECTION
@ TSE_SOME_ID
@ TSE_CLOSED
@ SO_RESTRICT_ENABLE
@ SO_FILTER_NO_LIB_OVERRIDE
@ SO_FILTER_NO_CHILDREN
@ SO_FILTER_NO_OBJECT
@ 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:544
void append(const T &value)
Definition: BLI_vector.hh:438
Base Class For Tree-Displays.
Definition: tree_display.hh:55
void operator()(TreeElement &collection_tree_elem)
ListBase buildTree(const TreeSourceData &source_data) override
TreeDisplayViewLayer(SpaceOutliner &space_outliner)
void * tree
ListBaseWrapper< T > List
@ TE_CHILD_NOT_IN_COLLECTION
#define SUPPORT_FILTER_OUTLINER(space_outliner_)
void outliner_free_tree(ListBase *tree)
#define TREESTORE(a)
TreeElement * outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, TreeElement *parent, short type, short index)
void outliner_make_object_parent_hierarchy(ListBase *lb)
struct Object * object
Definition: DNA_ID.h:273
ListBase layer_collections
struct Collection * collection
void * first
Definition: DNA_listBase.h:47
struct Object * parent
struct TreeElement * parent
ListBase subtree
void * directdata
const char * name
The data to build the tree from.
Definition: tree_display.h:39
struct Scene * scene
Definition: tree_display.h:41
struct ViewLayer * view_layer
Definition: tree_display.h:42
ListBase layer_collections
ListBase object_bases
Establish and manage Outliner trees for different display modes.