From ee3d36f78a59ebde397962d97fde4a4137f3aada Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 7 Sep 2022 12:05:56 +0200 Subject: Outliner: Initial (half working) port to new element storage Basicaly the idea is to have a C++ class to better manage the runtime tree element storage and access. This branch doesn't even compile yet, it's just an early experiment so far that I don't only want to keep locally. --- .../editors/space_outliner/outliner_dragdrop.cc | 12 +- .../editors/space_outliner/outliner_draw.cc | 145 ++++---- .../editors/space_outliner/outliner_intern.hh | 148 +++++++- .../editors/space_outliner/outliner_tree.cc | 387 +++++++++------------ .../editors/space_outliner/outliner_utils.cc | 27 +- .../editors/space_outliner/space_outliner.cc | 5 +- .../blender/editors/space_outliner/tree/common.cc | 31 +- .../blender/editors/space_outliner/tree/common.hh | 4 +- .../editors/space_outliner/tree/tree_display.hh | 35 +- .../space_outliner/tree/tree_display_data.cc | 6 +- .../space_outliner/tree/tree_display_libraries.cc | 33 +- .../space_outliner/tree/tree_display_orphaned.cc | 9 +- .../tree_display_override_library_hierarchies.cc | 40 +-- .../tree_display_override_library_properties.cc | 31 +- .../space_outliner/tree/tree_display_scenes.cc | 9 +- .../space_outliner/tree/tree_display_sequencer.cc | 11 +- .../space_outliner/tree/tree_display_view_layer.cc | 56 ++- .../editors/space_outliner/tree/tree_element.cc | 71 ++++ .../editors/space_outliner/tree/tree_element.hh | 26 +- .../space_outliner/tree/tree_element_anim_data.cc | 8 +- .../space_outliner/tree/tree_element_driver.cc | 3 +- .../editors/space_outliner/tree/tree_element_id.cc | 3 +- .../space_outliner/tree/tree_element_id_scene.cc | 12 +- .../space_outliner/tree/tree_element_nla.cc | 5 +- .../space_outliner/tree/tree_element_overrides.cc | 11 +- .../space_outliner/tree/tree_element_rna.cc | 16 +- .../tree/tree_element_scene_objects.cc | 4 +- .../space_outliner/tree/tree_element_seq.cc | 6 +- .../space_outliner/tree/tree_element_view_layer.cc | 2 +- 29 files changed, 646 insertions(+), 510 deletions(-) diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 4a0e00b8bf1..4f27af6bcea 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -64,9 +64,9 @@ static TreeElement *outliner_dropzone_element(TreeElement *te, } } /* Not it. Let's look at its children. */ - if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) { - LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) { - TreeElement *te_valid = outliner_dropzone_element(te_sub, fmval, children); + if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0) { + for (TreeElement &te_sub : te->child_elements) { + TreeElement *te_valid = outliner_dropzone_element(&te_sub, fmval, children); if (te_valid) { return te_valid; } @@ -139,14 +139,14 @@ static TreeElement *outliner_drop_insert_find(bContext *C, if (view_mval[1] < (te_hovered->ys + margin)) { if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) && - !BLI_listbase_is_empty(&te_hovered->subtree)) { + !te_hovered->child_elements.is_empty()) { /* inserting after a open item means we insert into it, but as first child */ - if (BLI_listbase_is_empty(&te_hovered->subtree)) { + if (te_hovered->child_elements.is_empty()) { *r_insert_type = TE_INSERT_INTO; return te_hovered; } *r_insert_type = TE_INSERT_BEFORE; - return static_cast(te_hovered->subtree.first); + return &*te_hovered->child_elements.begin(); } *r_insert_type = TE_INSERT_AFTER; return te_hovered; diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 3f99b19cd16..acddf2b2b1d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -81,22 +81,22 @@ namespace blender::ed::outliner { * \{ */ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner, - ListBase *lb, + SubTree &subtree, int *width, int *height) { - LISTBASE_FOREACH (TreeElement *, te, lb) { - *width = MAX2(*width, te->xend); + for (TreeElement &te : subtree) { + *width = MAX2(*width, te.xend); if (height != nullptr) { *height += UI_UNIT_Y; } - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(&te); if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height); + outliner_tree_dimensions_impl(space_outliner, te.child_elements, width, height); } else { - outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr); + outliner_tree_dimensions_impl(space_outliner, te.child_elements, width, nullptr); } } } @@ -105,7 +105,8 @@ void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int * { *r_width = 0; *r_height = 0; - outliner_tree_dimensions_impl(space_outliner, &space_outliner->tree, r_width, r_height); + outliner_tree_dimensions_impl( + space_outliner, space_outliner->runtime->root_elements, r_width, r_height); } /** @@ -1030,7 +1031,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, ViewLayer *view_layer, ARegion *region, SpaceOutliner *space_outliner, - ListBase *lb, + SubTree &subtree, RestrictPropertiesActive props_active_parent) { /* Get RNA properties (once for speed). */ @@ -1105,16 +1106,16 @@ static void outliner_draw_restrictbuts(uiBlock *block, /* Create buttons. */ uiBut *bt; - LISTBASE_FOREACH (TreeElement *, te, lb) { - TreeStoreElem *tselem = TREESTORE(te); + for (TreeElement &te : subtree) { + TreeStoreElem *tselem = TREESTORE(&te); RestrictPropertiesActive props_active = props_active_parent; - if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) { + if (te.ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te.ys <= region->v2d.cur.ymax) { if (tselem->type == TSE_R_LAYER && ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) { /* View layer render toggle. */ - ViewLayer *layer = static_cast(te->directdata); + ViewLayer *layer = static_cast(te.directdata); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, @@ -1122,7 +1123,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_RESTRICT_RENDER_OFF, (int)(region->v2d.cur.xmax - restrict_offsets.render), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &layer->flag, @@ -1136,18 +1137,18 @@ static void outliner_draw_restrictbuts(uiBlock *block, UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } } - else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) && - (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { + else if (((tselem->type == TSE_SOME_ID) && (te.idcode == ID_OB)) && + (te.flag & TE_CHILD_NOT_IN_COLLECTION)) { /* Don't show restrict columns for children that are not directly inside the collection. */ } - else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { + else if ((tselem->type == TSE_SOME_ID) && (te.idcode == ID_OB)) { PointerRNA ptr; Object *ob = (Object *)tselem->id; RNA_id_pointer_create(&ob->id, &ptr); if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) { - Base *base = (te->directdata) ? (Base *)te->directdata : - BKE_view_layer_base_find(view_layer, ob); + Base *base = (te.directdata) ? (Base *)te.directdata : + BKE_view_layer_base_find(view_layer, ob); if (base) { PointerRNA base_ptr; RNA_pointer_create(&scene->id, &RNA_ObjectBase, base, &base_ptr); @@ -1156,7 +1157,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.hide), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &base_ptr, @@ -1183,7 +1184,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.select), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1208,7 +1209,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1233,7 +1234,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.render), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1253,7 +1254,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (tselem->type == TSE_CONSTRAINT) { - bConstraint *con = (bConstraint *)te->directdata; + bConstraint *con = (bConstraint *)te.directdata; PointerRNA ptr; RNA_pointer_create(tselem->id, &RNA_Constraint, con, &ptr); @@ -1264,7 +1265,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.hide), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1282,7 +1283,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (tselem->type == TSE_MODIFIER) { - ModifierData *md = (ModifierData *)te->directdata; + ModifierData *md = (ModifierData *)te.directdata; PointerRNA ptr; RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); @@ -1293,7 +1294,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1316,7 +1317,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.render), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1335,7 +1336,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } else if (tselem->type == TSE_POSE_CHANNEL) { PointerRNA ptr; - bPoseChannel *pchan = (bPoseChannel *)te->directdata; + bPoseChannel *pchan = (bPoseChannel *)te.directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; bArmature *arm = static_cast(ob->data); @@ -1348,7 +1349,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &ptr, @@ -1372,7 +1373,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_RESTRICT_SELECT_OFF, (int)(region->v2d.cur.xmax - restrict_offsets.select), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), @@ -1389,7 +1390,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } else if (tselem->type == TSE_EBONE) { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = (EditBone *)te->directdata; + EditBone *ebone = (EditBone *)te.directdata; if (space_outliner->show_restrict_flags & SO_RESTRICT_VIEWPORT) { bt = uiDefIconButBitI(block, @@ -1398,7 +1399,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_RESTRICT_VIEW_OFF, (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), @@ -1420,7 +1421,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_RESTRICT_SELECT_OFF, (int)(region->v2d.cur.xmax - restrict_offsets.select), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), @@ -1437,7 +1438,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, } else if (tselem->type == TSE_GP_LAYER) { ID *id = tselem->id; - bGPDlayer *gpl = (bGPDlayer *)te->directdata; + bGPDlayer *gpl = (bGPDlayer *)te.directdata; if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) { bt = uiDefIconButBitS(block, @@ -1446,7 +1447,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_HIDE_OFF, (int)(region->v2d.cur.xmax - restrict_offsets.hide), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &gpl->flag, @@ -1467,7 +1468,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, ICON_UNLOCKED, (int)(region->v2d.cur.xmax - restrict_offsets.select), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &gpl->flag, @@ -1480,17 +1481,17 @@ static void outliner_draw_restrictbuts(uiBlock *block, UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); } } - else if (outliner_is_collection_tree_element(te)) { + else if (outliner_is_collection_tree_element(&te)) { PointerRNA collection_ptr; PointerRNA layer_collection_ptr; if (outliner_restrict_properties_collection_set( - scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { + scene, &te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - static_cast(te->directdata) : + static_cast(te.directdata) : nullptr; - Collection *collection = outliner_collection_from_tree_element(te); + Collection *collection = outliner_collection_from_tree_element(&te); if (layer_collection != nullptr) { if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) { @@ -1499,7 +1500,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax) - restrict_offsets.enable, - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &layer_collection_ptr, @@ -1519,7 +1520,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.hide), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &layer_collection_ptr, @@ -1548,7 +1549,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.holdout), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &layer_collection_ptr, @@ -1578,7 +1579,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.indirect_only), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &layer_collection_ptr, @@ -1610,7 +1611,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.viewport), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &collection_ptr, @@ -1647,7 +1648,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.render), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &collection_ptr, @@ -1682,7 +1683,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, (int)(region->v2d.cur.xmax - restrict_offsets.select), - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, &collection_ptr, @@ -1713,16 +1714,16 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } } - else if (outliner_is_collection_tree_element(te)) { + else if (outliner_is_collection_tree_element(&te)) { PointerRNA collection_ptr; PointerRNA layer_collection_ptr; outliner_restrict_properties_collection_set( - scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active); + scene, &te, &collection_ptr, &layer_collection_ptr, &props, &props_active); } if (TSELEM_OPEN(tselem, space_outliner)) { outliner_draw_restrictbuts( - block, scene, view_layer, region, space_outliner, &te->subtree, props_active); + block, scene, view_layer, region, space_outliner, te.child_elements, props_active); } } } @@ -1797,7 +1798,7 @@ static void outliner_draw_userbuts(uiBlock *block, static void outliner_draw_overrides_rna_buts(uiBlock *block, const ARegion *region, const SpaceOutliner *space_outliner, - const ListBase *lb, + const SubTree &subtree, const int x) { const float pad_x = 2.0f * UI_DPI_FAC; @@ -1805,17 +1806,17 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x); const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y); - LISTBASE_FOREACH (const TreeElement *, te, lb) { - const TreeStoreElem *tselem = TREESTORE(te); + for (const TreeElement &te : subtree) { + const TreeStoreElem *tselem = TREESTORE(&te); if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_draw_overrides_rna_buts(block, region, space_outliner, &te->subtree, x); + outliner_draw_overrides_rna_buts(block, region, space_outliner, te.child_elements, x); } - if (!outliner_is_element_in_view(te, ®ion->v2d)) { + if (!outliner_is_element_in_view(&te, ®ion->v2d)) { continue; } TreeElementOverridesProperty *override_elem = tree_element_cast( - te); + &te); if (!override_elem) { continue; } @@ -1826,7 +1827,7 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, 0, override_elem->rna_path.c_str(), x + pad_x, - te->ys + pad_y, + te.ys + pad_y, item_max_width, item_height, nullptr, @@ -1840,14 +1841,14 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, } if (const TreeElementOverridesPropertyOperation *override_op_elem = - tree_element_cast(te)) { + tree_element_cast(&te)) { StringRefNull op_label = override_op_elem->getOverrideOperationLabel(); uiDefBut(block, UI_BTYPE_LABEL, 0, op_label.c_str(), x + pad_x, - te->ys + pad_y, + te.ys + pad_y, item_max_width, item_height, nullptr, @@ -1870,7 +1871,7 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, (prop_type == PROP_ENUM) ? nullptr : "", ICON_NONE, x + pad_x, - te->ys + pad_y, + te.ys + pad_y, item_max_width, item_height); /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons @@ -1883,7 +1884,7 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension * arrays? */ uiDefAutoButsArrayR( - block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height); + block, ptr, prop, ICON_NONE, x + pad_x, te.ys + pad_y, item_max_width, item_height); } } } @@ -1906,19 +1907,20 @@ static void outliner_draw_overrides_restrictbuts(Main *bmain, uiBlock *block, const ARegion *region, const SpaceOutliner *space_outliner, - const ListBase *lb, + const SubTree &subtree, const int x) { - LISTBASE_FOREACH (const TreeElement *, te, lb) { - const TreeStoreElem *tselem = TREESTORE(te); + for (const TreeElement &te : subtree) { + const TreeStoreElem *tselem = TREESTORE(&te); if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_draw_overrides_restrictbuts(bmain, block, region, space_outliner, &te->subtree, x); + outliner_draw_overrides_restrictbuts( + bmain, block, region, space_outliner, te.child_elements, x); } - if (!outliner_is_element_in_view(te, ®ion->v2d)) { + if (!outliner_is_element_in_view(&te, ®ion->v2d)) { continue; } - TreeElementID *te_id = tree_element_cast(te); + TreeElementID *te_id = tree_element_cast(&te); if (!te_id) { continue; } @@ -1939,7 +1941,7 @@ static void outliner_draw_overrides_restrictbuts(Main *bmain, WM_OP_EXEC_DEFAULT, icon, x, - te->ys, + te.ys, UI_UNIT_X, UI_UNIT_Y, ""); @@ -3946,12 +3948,13 @@ void draw_outliner(const bContext *C) if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_PROPERTIES) { UI_block_emboss_set(block, UI_EMBOSS); UI_block_flag_enable(block, UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE); - outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x); + outliner_draw_overrides_rna_buts( + block, region, space_outliner, space_outliner->runtime->root_elements, x); UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); } else if (space_outliner->lib_override_view_mode == SO_LIB_OVERRIDE_VIEW_HIERARCHIES) { outliner_draw_overrides_restrictbuts( - mainvar, block, region, space_outliner, &space_outliner->tree, x); + mainvar, block, region, space_outliner, space_outliner->runtime->root_elements, x); } } else if (right_column_width > 0.0f) { @@ -3963,7 +3966,7 @@ void draw_outliner(const bContext *C) tvc.view_layer, region, space_outliner, - &space_outliner->tree, + space_outliner->runtime->root_elements, props_active); } diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh index ad5d653949c..c67f7c9ff93 100644 --- a/source/blender/editors/space_outliner/outliner_intern.hh +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -7,6 +7,8 @@ #pragma once +#include +#include #include #include "RNA_types.h" @@ -40,10 +42,132 @@ namespace blender::ed::outliner { class AbstractTreeDisplay; class AbstractTreeElement; +struct SpaceOutliner_Runtime; +struct TreeElement; namespace treehash = blender::bke::outliner::treehash; -struct TreeElement; +/** + * Container to own a number of tree elements. + */ +class SubTree { + /** The tree element owning this sub-tree. Remains null for root level elements. */ + TreeElement *parent_ = nullptr; + + std::list> elements_; + + /* TODO all this boilerplate... make this a generic indirect-iterator? */ + template class IteratorBase { + public: + NestedIterT iter_; + + using iterator_category = std::forward_iterator_tag; + using value_type = ElemT; + using difference_type = ptrdiff_t; + using pointer = ElemT *; + using reference = ElemT &; + + explicit IteratorBase(NestedIterT iter) : iter_(iter) + { + } + + ElemT &operator*() + { + return **iter_; + } + ElemT *operator->() + { + return &**iter_; + } + IterT &operator++() + { + ++iter_; + return *static_cast(this); + } + IterT &operator--() + { + --iter_; + return *static_cast(this); + } + IterT operator++(int) + { + IterT tmp = *this; + ++iter_; + return tmp; + } + IterT operator--(int) + { + IterT tmp = *this; + --iter_; + return tmp; + } + friend bool operator==(const IterT &a, const IterT &b) + { + return a.iter_ == b.iter_; + } + friend bool operator!=(const IterT &a, const IterT &b) + { + return a.iter_ != b.iter_; + } + }; + + class Iterator : public IteratorBase { + using IteratorBase::IteratorBase; + }; + class ConstIterator : public IteratorBase { + using IteratorBase::IteratorBase; + }; + + public: + using iterator = Iterator; + using const_iterator = Iterator; + + Iterator begin() + { + return Iterator{elements_.begin()}; + } + std::reverse_iterator rbegin() + { + return std::reverse_iterator(Iterator{elements_.end()}); + } + Iterator end() + { + return Iterator{elements_.end()}; + } + std::reverse_iterator rend() + { + return std::reverse_iterator(Iterator{elements_.begin()}); + } + ConstIterator begin() const + { + return ConstIterator{elements_.begin()}; + } + ConstIterator end() const + { + return ConstIterator{elements_.end()}; + } + + explicit SubTree(TreeElement &parent); + explicit SubTree(SpaceOutliner_Runtime &root); + + void add_back(std::unique_ptr elem); + void insert_before(Iterator pos, std::unique_ptr elem); + /** Detaches the given element from this sub-tree, and moves ownership of it to the calling + * scope (by returning its unique pointer). This way the caller can decide to keep it still, + * for example to reinsert it elsewhere. If the caller doesn't use it (e.g. by ignoring the + * return value entirely), the element will be destructed and freed cleanly. */ + std::unique_ptr remove(TreeElement &element); + /** Erase and destruct all elements in the container. */ + void clear(); + + bool has_child(const TreeElement &needle) const; + + bool is_empty() const; + /** Get the element owning these children. Will return null in case of root level elements. */ + TreeElement *parent() const; +}; struct SpaceOutliner_Runtime { /** Object to create and manage the tree for a specific display type (View Layers, Scenes, @@ -53,7 +177,11 @@ struct SpaceOutliner_Runtime { /* Hash table for tree-store elements, using `(id, type, index)` as key. */ std::unique_ptr tree_hash; - SpaceOutliner_Runtime() = default; + /** Entry point for the outliner tree. This is essentially a sorted vector of #TreeElement's, + * whereby each can have its own #SubTree containing the same. */ + SubTree root_elements; + + SpaceOutliner_Runtime(); /** Used for copying runtime data to a duplicated space. */ SpaceOutliner_Runtime(const SpaceOutliner_Runtime &); ~SpaceOutliner_Runtime() = default; @@ -76,6 +204,12 @@ enum TreeTraversalAction { typedef TreeTraversalAction (*TreeTraversalFunc)(TreeElement *te, void *customdata); +/** + * Legacy representation of an item in the Outliner tree. The new representation is + * #AbstractTreeElement, efforts should be put into slowly transitioning to it. However, since not + * all tree element types support this yet (#TreeElement.abstract_element will be null), things are + * split between the too, and the situation is rather chaotic. + */ struct TreeElement { TreeElement *next, *prev, *parent; @@ -88,6 +222,9 @@ struct TreeElement { std::unique_ptr abstract_element; ListBase subtree; + + SubTree child_elements; + int xs, ys; /* Do selection. */ TreeStoreElem *store_elem; /* Element in tree store. */ short flag; /* Flag for non-saved stuff. */ @@ -96,6 +233,10 @@ struct TreeElement { short xend; /* Width of item display, for select. */ const char *name; void *directdata; /* Armature Bones, Base, ... */ + + TreeElement() : child_elements(*this) + { + } }; struct TreeElementIcon { @@ -254,7 +395,6 @@ enum TreeItemSelectAction { /* outliner_tree.c ----------------------------------------------- */ -void outliner_free_tree(ListBase *tree); void outliner_cleanup_tree(struct SpaceOutliner *space_outliner); /** * Free \a element and its sub-tree and remove its link in \a parent_subtree. @@ -262,7 +402,7 @@ void outliner_cleanup_tree(struct SpaceOutliner *space_outliner); * \note Does not remove the #TreeStoreElem of \a element! * \param parent_subtree: Sub-tree of the parent element, so the list containing \a element. */ -void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree); +void outliner_free_tree_element(TreeElement *element, SubTree &parent_subtree); /** * Main entry point for building the tree data-structure that the outliner represents. diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index 070df284c6f..42ead451354 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -140,7 +140,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) } static void check_persistent( - SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr) + SpaceOutliner *space_outliner, TreeElement &te, ID *id, short type, short nr) { if (space_outliner->treestore == nullptr) { /* if treestore was not created in readfile.c, create it here */ @@ -156,7 +156,7 @@ static void check_persistent( * (note that there may be multiple unused elements in case of linked objects) */ TreeStoreElem *tselem = space_outliner->runtime->tree_hash->lookup_unused(type, nr, id); if (tselem) { - te->store_elem = tselem; + te.store_elem = tselem; tselem->used = 1; return; } @@ -168,7 +168,7 @@ static void check_persistent( tselem->id = id; tselem->used = 0; tselem->flag = TSE_CLOSED; - te->store_elem = tselem; + te.store_elem = tselem; space_outliner->runtime->tree_hash->add_element(*tselem); } @@ -178,31 +178,20 @@ static void check_persistent( /** \name Tree Management * \{ */ -void outliner_free_tree(ListBase *tree) -{ - LISTBASE_FOREACH_MUTABLE (TreeElement *, element, tree) { - outliner_free_tree_element(element, tree); - } -} - void outliner_cleanup_tree(SpaceOutliner *space_outliner) { - outliner_free_tree(&space_outliner->tree); + space_outliner->runtime->root_elements.clear(); outliner_storage_cleanup(space_outliner); } -void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) +void outliner_free_tree_element(TreeElement *element, SubTree &parent_subtree) { - BLI_assert(BLI_findindex(parent_subtree, element) > -1); - BLI_remlink(parent_subtree, element); - - outliner_free_tree(&element->subtree); + BLI_assert(parent_subtree.has_child(*element)); + parent_subtree.remove(*element); if (element->flag & TE_FREE_NAME) { MEM_freeN((void *)element->name); } - element->abstract_element = nullptr; - MEM_delete(element); } /* ********************************************************* */ @@ -218,29 +207,22 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s } /* special handling of hierarchical non-lib data */ -static void outliner_add_bone(SpaceOutliner *space_outliner, - ListBase *lb, - ID *id, - Bone *curBone, - TreeElement *parent, - int *a) +static void outliner_add_bone( + SpaceOutliner *space_outliner, ID *id, Bone *curBone, TreeElement *parent, int *a) { - TreeElement *te = outliner_add_element(space_outliner, lb, id, parent, TSE_BONE, *a); + TreeElement *te = outliner_add_element(space_outliner, id, parent, TSE_BONE, *a); (*a)++; te->name = curBone->name; te->directdata = curBone; LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) { - outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a); + outliner_add_bone(space_outliner, id, child_bone, te, a); } } #ifdef WITH_FREESTYLE -static void outliner_add_line_styles(SpaceOutliner *space_outliner, - ListBase *lb, - Scene *sce, - TreeElement *te) +static void outliner_add_line_styles(SpaceOutliner *space_outliner, Scene *sce, TreeElement *te) { ViewLayer *view_layer; FreestyleLineSet *lineset; @@ -261,7 +243,7 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner, continue; } linestyle->id.tag &= ~LIB_TAG_DOIT; - outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, linestyle, te, TSE_SOME_ID, 0); } } } @@ -275,18 +257,17 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, Object *ob) { if (outliner_animdata_test(ob->adt)) { - outliner_add_element(space_outliner, &te->subtree, ob, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, ob, te, TSE_ANIM_DATA, 0); } /* FIXME: add a special type for this. */ - outliner_add_element(space_outliner, &te->subtree, ob->poselib, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, ob->poselib, te, TSE_SOME_ID, 0); - outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { bArmature *arm = static_cast(ob->data); - TreeElement *tenla = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0); + TreeElement *tenla = outliner_add_element(space_outliner, ob, te, TSE_POSE_BASE, 0); tenla->name = IFACE_("Pose"); /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ @@ -294,8 +275,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, int const_index = 1000; /* ensure unique id for bone constraints */ int a; LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) { - TreeElement *ten = outliner_add_element( - space_outliner, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a); + TreeElement *ten = outliner_add_element(space_outliner, ob, tenla, TSE_POSE_CHANNEL, a); ten->name = pchan->name; ten->directdata = pchan; pchan->temp = (void *)ten; @@ -303,13 +283,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, if (!BLI_listbase_is_empty(&pchan->constraints)) { /* Object *target; */ TreeElement *tenla1 = outliner_add_element( - space_outliner, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); + space_outliner, ob, ten, TSE_CONSTRAINT_BASE, 0); tenla1->name = IFACE_("Constraints"); /* char *str; */ LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { TreeElement *ten1 = outliner_add_element( - space_outliner, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); + space_outliner, ob, tenla1, TSE_CONSTRAINT, const_index); #if 0 /* disabled as it needs to be reworked for recoded constraints system */ target = get_constraint_target(con, &str); if (str && str[0]) { @@ -349,14 +329,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* Pose Groups */ if (!BLI_listbase_is_empty(&ob->pose->agroups)) { - TreeElement *ten_bonegrp = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0); + TreeElement *ten_bonegrp = outliner_add_element(space_outliner, ob, te, TSE_POSEGRP_BASE, 0); ten_bonegrp->name = IFACE_("Bone Groups"); int index; LISTBASE_FOREACH_INDEX (bActionGroup *, agrp, &ob->pose->agroups, index) { TreeElement *ten = outliner_add_element( - space_outliner, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, index); + space_outliner, ob, ten_bonegrp, TSE_POSEGRP, index); ten->name = agrp->name; ten->directdata = agrp; } @@ -364,18 +343,16 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < ob->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a); + outliner_add_element(space_outliner, ob->mat[a], te, TSE_SOME_ID, a); } if (!BLI_listbase_is_empty(&ob->constraints)) { - TreeElement *tenla = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0); + TreeElement *tenla = outliner_add_element(space_outliner, ob, te, TSE_CONSTRAINT_BASE, 0); tenla->name = IFACE_("Constraints"); int index; LISTBASE_FOREACH_INDEX (bConstraint *, con, &ob->constraints, index) { - TreeElement *ten = outliner_add_element( - space_outliner, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, index); + TreeElement *ten = outliner_add_element(space_outliner, ob, tenla, TSE_CONSTRAINT, index); #if 0 /* disabled due to constraints system targets recode... code here needs review */ target = get_constraint_target(con, &str); if (str && str[0]) { @@ -395,54 +372,36 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } if (!BLI_listbase_is_empty(&ob->modifiers)) { - TreeElement *ten_mod = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); + TreeElement *ten_mod = outliner_add_element(space_outliner, ob, te, TSE_MODIFIER_BASE, 0); ten_mod->name = IFACE_("Modifiers"); int index; LISTBASE_FOREACH_INDEX (ModifierData *, md, &ob->modifiers, index) { - TreeElement *ten = outliner_add_element( - space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index); + TreeElement *ten = outliner_add_element(space_outliner, ob, ten_mod, TSE_MODIFIER, index); ten->name = md->name; ten->directdata = md; if (md->type == eModifierType_Lattice) { - outliner_add_element(space_outliner, - &ten->subtree, - ((LatticeModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((LatticeModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eModifierType_Curve) { - outliner_add_element(space_outliner, - &ten->subtree, - ((CurveModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((CurveModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eModifierType_Armature) { - outliner_add_element(space_outliner, - &ten->subtree, - ((ArmatureModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((ArmatureModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eModifierType_Hook) { - outliner_add_element(space_outliner, - &ten->subtree, - ((HookModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((HookModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eModifierType_ParticleSystem) { ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; TreeElement *ten_psys; - ten_psys = outliner_add_element(space_outliner, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0); + ten_psys = outliner_add_element(space_outliner, ob, te, TSE_LINKED_PSYS, 0); ten_psys->directdata = psys; ten_psys->name = psys->part->id.name + 2; } @@ -451,64 +410,45 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* Grease Pencil modifiers. */ if (!BLI_listbase_is_empty(&ob->greasepencil_modifiers)) { - TreeElement *ten_mod = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); + TreeElement *ten_mod = outliner_add_element(space_outliner, ob, te, TSE_MODIFIER_BASE, 0); ten_mod->name = IFACE_("Modifiers"); int index; LISTBASE_FOREACH_INDEX (GpencilModifierData *, md, &ob->greasepencil_modifiers, index) { - TreeElement *ten = outliner_add_element( - space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index); + TreeElement *ten = outliner_add_element(space_outliner, ob, ten_mod, TSE_MODIFIER, index); ten->name = md->name; ten->directdata = md; if (md->type == eGpencilModifierType_Armature) { - outliner_add_element(space_outliner, - &ten->subtree, - ((ArmatureGpencilModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((ArmatureGpencilModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eGpencilModifierType_Hook) { - outliner_add_element(space_outliner, - &ten->subtree, - ((HookGpencilModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((HookGpencilModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } else if (md->type == eGpencilModifierType_Lattice) { - outliner_add_element(space_outliner, - &ten->subtree, - ((LatticeGpencilModifierData *)md)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((LatticeGpencilModifierData *)md)->object, ten, TSE_LINKED_OB, 0); } } } /* Grease Pencil effects. */ if (!BLI_listbase_is_empty(&ob->shader_fx)) { - TreeElement *ten_fx = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_GPENCIL_EFFECT_BASE, 0); + TreeElement *ten_fx = outliner_add_element(space_outliner, ob, te, TSE_GPENCIL_EFFECT_BASE, 0); ten_fx->name = IFACE_("Effects"); int index; LISTBASE_FOREACH_INDEX (ShaderFxData *, fx, &ob->shader_fx, index) { TreeElement *ten = outliner_add_element( - space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_GPENCIL_EFFECT, index); + space_outliner, ob, ten_fx, TSE_GPENCIL_EFFECT, index); ten->name = fx->name; ten->directdata = fx; if (fx->type == eShaderFxType_Swirl) { - outliner_add_element(space_outliner, - &ten->subtree, - ((SwirlShaderFxData *)fx)->object, - ten, - TSE_LINKED_OB, - 0); + outliner_add_element( + space_outliner, ((SwirlShaderFxData *)fx)->object, ten, TSE_LINKED_OB, 0); } } } @@ -517,14 +457,12 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, if (ELEM(ob->type, OB_MESH, OB_GPENCIL, OB_LATTICE)) { const ListBase *defbase = BKE_object_defgroup_list(ob); if (!BLI_listbase_is_empty(defbase)) { - TreeElement *tenla = outliner_add_element( - space_outliner, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); + TreeElement *tenla = outliner_add_element(space_outliner, ob, te, TSE_DEFGROUP_BASE, 0); tenla->name = IFACE_("Vertex Groups"); int index; LISTBASE_FOREACH_INDEX (bDeformGroup *, defgroup, defbase, index) { - TreeElement *ten = outliner_add_element( - space_outliner, &tenla->subtree, ob, tenla, TSE_DEFGROUP, index); + TreeElement *ten = outliner_add_element(space_outliner, ob, tenla, TSE_DEFGROUP, index); ten->name = defgroup->name; ten->directdata = defgroup; } @@ -533,20 +471,19 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* duplicated group */ if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { - outliner_add_element( - space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, ob->instance_collection, te, TSE_SOME_ID, 0); } } /* Can be inlined if necessary. */ static void outliner_add_id_contents(SpaceOutliner *space_outliner, - TreeElement *te, + TreeElement &te, TreeStoreElem *tselem, ID *id) { /* tuck pointer back in object, to construct hierarchy */ if (GS(id->name) == ID_OB) { - id->newid = (ID *)te; + id->newid = (ID *)&te; } /* expand specific data always */ @@ -556,19 +493,19 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, BLI_assert_msg(0, "ID type expected to be expanded through new tree-element design"); break; case ID_OB: { - outliner_add_object_contents(space_outliner, te, tselem, (Object *)id); + outliner_add_object_contents(space_outliner, &te, tselem, (Object *)id); break; } case ID_ME: { Mesh *me = (Mesh *)id; if (outliner_animdata_test(me->adt)) { - outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, me, &te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, me->key, &te, TSE_SOME_ID, 0); for (int a = 0; a < me->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a); + outliner_add_element(space_outliner, me->mat[a], &te, TSE_SOME_ID, a); } /* could do tfaces with image links, but the images are not grouped nicely. * would require going over all tfaces, sort images in use. etc... */ @@ -578,11 +515,11 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, Curve *cu = (Curve *)id; if (outliner_animdata_test(cu->adt)) { - outliner_add_element(space_outliner, &te->subtree, cu, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, cu, &te, TSE_ANIM_DATA, 0); } for (int a = 0; a < cu->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a); + outliner_add_element(space_outliner, cu->mat[a], &te, TSE_SOME_ID, a); } break; } @@ -590,40 +527,40 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, MetaBall *mb = (MetaBall *)id; if (outliner_animdata_test(mb->adt)) { - outliner_add_element(space_outliner, &te->subtree, mb, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, mb, &te, TSE_ANIM_DATA, 0); } for (int a = 0; a < mb->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a); + outliner_add_element(space_outliner, mb->mat[a], &te, TSE_SOME_ID, a); } break; } case ID_MA: { Material *ma = (Material *)id; if (outliner_animdata_test(ma->adt)) { - outliner_add_element(space_outliner, &te->subtree, ma, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, ma, &te, TSE_ANIM_DATA, 0); } break; } case ID_TE: { Tex *tex = (Tex *)id; if (outliner_animdata_test(tex->adt)) { - outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, tex, &te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, tex->ima, &te, TSE_SOME_ID, 0); break; } case ID_CA: { Camera *ca = (Camera *)id; if (outliner_animdata_test(ca->adt)) { - outliner_add_element(space_outliner, &te->subtree, ca, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, ca, &te, TSE_ANIM_DATA, 0); } break; } case ID_CF: { CacheFile *cache_file = (CacheFile *)id; if (outliner_animdata_test(cache_file->adt)) { - outliner_add_element(space_outliner, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, cache_file, &te, TSE_ANIM_DATA, 0); } break; @@ -631,35 +568,35 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, case ID_LA: { Light *la = (Light *)id; if (outliner_animdata_test(la->adt)) { - outliner_add_element(space_outliner, &te->subtree, la, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, la, &te, TSE_ANIM_DATA, 0); } break; } case ID_SPK: { Speaker *spk = (Speaker *)id; if (outliner_animdata_test(spk->adt)) { - outliner_add_element(space_outliner, &te->subtree, spk, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, spk, &te, TSE_ANIM_DATA, 0); } break; } case ID_LP: { LightProbe *prb = (LightProbe *)id; if (outliner_animdata_test(prb->adt)) { - outliner_add_element(space_outliner, &te->subtree, prb, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, prb, &te, TSE_ANIM_DATA, 0); } break; } case ID_WO: { World *wrld = (World *)id; if (outliner_animdata_test(wrld->adt)) { - outliner_add_element(space_outliner, &te->subtree, wrld, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, wrld, &te, TSE_ANIM_DATA, 0); } break; } case ID_KE: { Key *key = (Key *)id; if (outliner_animdata_test(key->adt)) { - outliner_add_element(space_outliner, &te->subtree, key, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, key, &te, TSE_ANIM_DATA, 0); } break; } @@ -672,14 +609,13 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, bArmature *arm = (bArmature *)id; if (outliner_animdata_test(arm->adt)) { - outliner_add_element(space_outliner, &te->subtree, arm, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, arm, &te, TSE_ANIM_DATA, 0); } if (arm->edbo) { int a = 0; LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm->edbo, a) { - TreeElement *ten = outliner_add_element( - space_outliner, &te->subtree, id, te, TSE_EBONE, a); + TreeElement *ten = outliner_add_element(space_outliner, id, &te, TSE_EBONE, a); ten->directdata = ebone; ten->name = ebone->name; ebone->temp.p = ten; @@ -689,20 +625,21 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, static_cast(((EditBone *)arm->edbo->first)->temp.p) : nullptr; while (ten) { - TreeElement *nten = ten->next, *par; + TreeElement *nten = ten->next; + EditBone *ebone = (EditBone *)ten->directdata; if (ebone->parent) { - BLI_remlink(&te->subtree, ten); - par = static_cast(ebone->parent->temp.p); - BLI_addtail(&par->subtree, ten); - ten->parent = par; + std::unique_ptr ten_uptr = te.child_elements.remove(*ten); + + TreeElement *new_parent = static_cast(ebone->parent->temp.p); + new_parent->child_elements.add_back(std::move(ten_uptr)); } ten = nten; } } else { /* do not extend Armature when we have posemode */ - tselem = TREESTORE(te->parent); + tselem = TREESTORE(te.parent); if (TSE_IS_REAL_ID(tselem) && GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) { /* pass */ @@ -710,7 +647,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, else { int a = 0; LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - outliner_add_bone(space_outliner, &te->subtree, id, bone, te, &a); + outliner_add_bone(space_outliner, id, bone, &te, &a); } } } @@ -720,12 +657,12 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; if (outliner_animdata_test(linestyle->adt)) { - outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, linestyle, &te, TSE_ANIM_DATA, 0); } for (int a = 0; a < MAX_MTEX; a++) { if (linestyle->mtex[a]) { - outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a); + outliner_add_element(space_outliner, linestyle->mtex[a]->tex, &te, 0, a); } } break; @@ -734,50 +671,50 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, bGPdata *gpd = (bGPdata *)id; if (outliner_animdata_test(gpd->adt)) { - outliner_add_element(space_outliner, &te->subtree, gpd, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, gpd, &te, TSE_ANIM_DATA, 0); } /* TODO: base element for layers? */ int index = 0; LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd->layers) { - outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, index); + outliner_add_element(space_outliner, gpl, &te, TSE_GP_LAYER, index); index++; } break; } case ID_GR: { /* Don't expand for instances, creates too many elements. */ - if (!(te->parent && te->parent->idcode == ID_OB)) { + if (!(te.parent && te.parent->idcode == ID_OB)) { Collection *collection = (Collection *)id; - outliner_add_collection_recursive(space_outliner, collection, te); + outliner_add_collection_recursive(space_outliner, collection, &te); } break; } case ID_CV: { Curves *curves = (Curves *)id; if (outliner_animdata_test(curves->adt)) { - outliner_add_element(space_outliner, &te->subtree, curves, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, curves, &te, TSE_ANIM_DATA, 0); } break; } case ID_PT: { PointCloud *pointcloud = (PointCloud *)id; if (outliner_animdata_test(pointcloud->adt)) { - outliner_add_element(space_outliner, &te->subtree, pointcloud, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, pointcloud, &te, TSE_ANIM_DATA, 0); } break; } case ID_VO: { Volume *volume = (Volume *)id; if (outliner_animdata_test(volume->adt)) { - outliner_add_element(space_outliner, &te->subtree, volume, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, volume, &te, TSE_ANIM_DATA, 0); } break; } case ID_SIM: { Simulation *simulation = (Simulation *)id; if (outliner_animdata_test(simulation->adt)) { - outliner_add_element(space_outliner, &te->subtree, simulation, te, TSE_ANIM_DATA, 0); + outliner_add_element(space_outliner, simulation, &te, TSE_ANIM_DATA, 0); } break; } @@ -787,7 +724,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } TreeElement *outliner_add_element(SpaceOutliner *space_outliner, - ListBase *lb, void *idv, TreeElement *parent, short type, @@ -823,27 +759,38 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, BLI_assert(TREESTORE_ID_TYPE(id)); } - TreeElement *te = MEM_new(__func__); - /* add to the visual tree */ - BLI_addtail(lb, te); + std::unique_ptr te_uptr = std::make_unique(); + TreeElement &te = *te_uptr; + + /* Add to the visual tree. Moves ownership the the proper element storage. */ + if (parent) { + parent->child_elements.add_back(std::move(te_uptr)); + } + else { + space_outliner->runtime->root_elements.add_back(std::move(te_uptr)); + } + /* add to the storage */ check_persistent(space_outliner, te, id, type, index); - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(&te); /* if we are searching for something expand to see child elements */ if (SEARCHING_OUTLINER(space_outliner)) { tselem->flag |= TSE_CHILDSEARCH; } - te->parent = parent; - te->index = index; /* For data arrays. */ + if (te.parent != parent) { + printf("error\n"); + } + BLI_assert(te.parent == parent); + te.index = index; /* For data arrays. */ /* New inheritance based element representation. Not all element types support this yet, * eventually it should replace #TreeElement entirely. */ - te->abstract_element = AbstractTreeElement::createFromType(type, *te, idv); - if (te->abstract_element) { + te.abstract_element = AbstractTreeElement::createFromType(type, te, idv); + if (te.abstract_element) { /* Element types ported to the new design are expected to have their name set at this point! */ - BLI_assert(te->name != nullptr); + BLI_assert(te.name != nullptr); } if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { @@ -865,7 +812,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* pass */ } else if (type == TSE_SOME_ID) { - if (!te->abstract_element) { + if (!te.abstract_element) { BLI_assert_msg(0, "Expected this ID type to be ported to new Outliner tree-element design"); } } @@ -873,7 +820,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, TSE_LIBRARY_OVERRIDE_BASE, TSE_LIBRARY_OVERRIDE, TSE_LIBRARY_OVERRIDE_OPERATION)) { - if (!te->abstract_element) { + if (!te.abstract_element) { BLI_assert_msg(0, "Expected override types to be ported to new Outliner tree-element design"); } @@ -884,21 +831,21 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, /* The new type design sets the name already, don't override that here. We need to figure out * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */ - if (!te->abstract_element) { - te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ + if (!te.abstract_element) { + te.name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ } - te->idcode = GS(id->name); + te.idcode = GS(id->name); } if (!expand) { /* Pass */ } - else if (te->abstract_element && te->abstract_element->isExpandValid()) { - tree_element_expand(*te->abstract_element, *space_outliner); + else if (te.abstract_element && te.abstract_element->isExpandValid()) { + tree_element_expand(*te.abstract_element, *space_outliner); } else if (type == TSE_SOME_ID) { /* ID types not (fully) ported to new design yet. */ - if (te->abstract_element->expandPoll(*space_outliner)) { + if (te.abstract_element->expandPoll(*space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); } } @@ -919,7 +866,17 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design"); } - return te; + return &te; +} + +TreeElement *outliner_add_element(SpaceOutliner *space_outliner, + void *idv, + SubTree &subtree, + short type, + short index, + const bool expand) +{ + return outliner_add_element(space_outliner, idv, subtree.parent(), type, index, expand); } /* ======================================================= */ @@ -931,12 +888,11 @@ BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collec } BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, - ListBase *tree, Collection *collection, TreeElement *parent) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, cob->ob, parent, TSE_SOME_ID, 0); } } @@ -947,12 +903,11 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, outliner_add_collection_init(ten, collection); LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - outliner_add_element( - space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0); + outliner_add_element(space_outliner, &child->collection->id, ten, TSE_SOME_ID, 0); } if (space_outliner->outlinevis != SO_SCENES) { - outliner_add_collection_objects(space_outliner, &ten->subtree, collection, ten); + outliner_add_collection_objects(space_outliner, collection, ten); } return ten; @@ -1504,7 +1459,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, return true; } -static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags) +static bool outliner_filter_has_name(const TreeElement &te, const char *name, int flags) { int fn_flag = 0; @@ -1512,7 +1467,7 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag fn_flag |= FNM_CASEFOLD; } - return fnmatch(name, te->name, fn_flag) == 0; + return fnmatch(name, te.name, fn_flag) == 0; } static bool outliner_element_is_collection_or_object(TreeElement *te) @@ -1531,54 +1486,57 @@ static bool outliner_element_is_collection_or_object(TreeElement *te) return false; } -static TreeElement *outliner_extract_children_from_subtree(TreeElement *element, - ListBase *parent_subtree) +static SubTree::iterator outliner_extract_children_from_subtree( + SubTree::iterator te_iter, + /* The tree the given elemet is in. */ + SubTree &parent_tree) { - TreeElement *te_next = element->next; + TreeElement &te = *te_iter; + SubTree::iterator te_next = std::next(te_iter); + + BLI_assert(parent_tree.has_child(te)); - if (outliner_element_is_collection_or_object(element)) { - TreeElement *te_prev = nullptr; - for (TreeElement *te = static_cast(element->subtree.last); te; te = te_prev) { - te_prev = te->prev; + if (outliner_element_is_collection_or_object(&te)) { + for (std::reverse_iterator child_iter = te.child_elements.rbegin(); + child_iter != te.child_elements.rend(); + ++child_iter) { + TreeElement &child = *child_iter; - if (!outliner_element_is_collection_or_object(te)) { + if (!outliner_element_is_collection_or_object(&child)) { continue; } - te_next = te; - BLI_remlink(&element->subtree, te); - BLI_insertlinkafter(parent_subtree, element->prev, te); - te->parent = element->parent; + std::unique_ptr floating_child = te.child_elements.remove(child); + parent_tree.insert_before(te_iter, std::move(floating_child)); + te_next = child_iter.base(); } } - outliner_free_tree_element(element, parent_subtree); + parent_tree.remove(te); return te_next; } static int outliner_filter_subtree(SpaceOutliner *space_outliner, ViewLayer *view_layer, - ListBase *lb, + SubTree &subtree, const char *search_string, const int exclude_filter) { - TreeElement *te, *te_next; - TreeStoreElem *tselem; + for (SubTree::iterator te_iter = subtree.begin(); te_iter != subtree.end(); ++te_iter) { + TreeElement &te = *te_iter; - for (te = static_cast(lb->first); te; te = te_next) { - te_next = te->next; - if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { + if ((outliner_element_visible_get(view_layer, &te, exclude_filter) == false)) { /* Don't free the tree, but extract the children from the parent and add to this tree. */ /* This also needs filtering the subtree prior (see T69246). */ outliner_filter_subtree( - space_outliner, view_layer, &te->subtree, search_string, exclude_filter); - te_next = outliner_extract_children_from_subtree(te, lb); + space_outliner, view_layer, te.child_elements, search_string, exclude_filter); + te_iter = outliner_extract_children_from_subtree(te_iter, subtree); continue; } if ((exclude_filter & SO_FILTER_SEARCH) == 0) { /* Filter subtree too. */ outliner_filter_subtree( - space_outliner, view_layer, &te->subtree, search_string, exclude_filter); + space_outliner, view_layer, te.child_elements, search_string, exclude_filter); continue; } @@ -1589,31 +1547,31 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner, * - otherwise, we can't see within the subtree and the item doesn't match, * so these can be safely ignored (i.e. the subtree can get freed) */ - tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(&te); /* flag as not a found item */ tselem->flag &= ~TSE_SEARCHMATCH; if ((!TSELEM_OPEN(tselem, space_outliner)) || outliner_filter_subtree( - space_outliner, view_layer, &te->subtree, search_string, exclude_filter) == 0) { - outliner_free_tree_element(te, lb); + space_outliner, view_layer, te.child_elements, search_string, exclude_filter) == 0) { + subtree.remove(te); } } else { - tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(&te); /* flag as a found item - we can then highlight it */ tselem->flag |= TSE_SEARCHMATCH; /* filter subtree too */ outliner_filter_subtree( - space_outliner, view_layer, &te->subtree, search_string, exclude_filter); + space_outliner, view_layer, te.child_elements, search_string, exclude_filter); } } /* if there are still items in the list, that means that there were still some matches */ - return (BLI_listbase_is_empty(lb) == false); + return !subtree.is_empty(); } static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer) @@ -1636,8 +1594,11 @@ static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_ search_string = search_buff; } - outliner_filter_subtree( - space_outliner, view_layer, &space_outliner->tree, search_string, exclude_filter); + outliner_filter_subtree(space_outliner, + view_layer, + space_outliner->runtime->root_elements, + search_string, + exclude_filter); } static void outliner_clear_newid_from_main(Main *bmain) @@ -1691,8 +1652,7 @@ void outliner_build_tree(Main *mainvar, OutlinerTreeElementFocus focus; outliner_store_scrolling_position(space_outliner, region, &focus); - outliner_free_tree(&space_outliner->tree); - outliner_storage_cleanup(space_outliner); + outliner_cleanup_tree(space_outliner); space_outliner->runtime->tree_display = AbstractTreeDisplay::createFromDisplayMode( space_outliner->outlinevis, *space_outliner); @@ -1701,7 +1661,8 @@ void outliner_build_tree(Main *mainvar, BLI_assert(space_outliner->runtime->tree_display != nullptr); TreeSourceData source_data{*mainvar, *scene, *view_layer}; - space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data); + space_outliner->runtime->root_elements = space_outliner->runtime->tree_display->buildTree( + source_data); if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) { outliner_sort(&space_outliner->tree); diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc index ff5292e2883..dd29fedaef2 100644 --- a/source/blender/editors/space_outliner/outliner_utils.cc +++ b/source/blender/editors/space_outliner/outliner_utils.cc @@ -70,8 +70,7 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner, return te_iter; } - if (BLI_listbase_is_empty(&te_iter->subtree) || - !TSELEM_OPEN(TREESTORE(te_iter), space_outliner)) { + if (te_iter->child_elements.is_empty() || !TSELEM_OPEN(TREESTORE(te_iter), space_outliner)) { /* No need for recursion. */ continue; } @@ -95,35 +94,31 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner, return nullptr; } -static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te, +static TreeElement *outliner_find_item_at_x_in_row_recursive(TreeElement *parent_te, float view_co_x, bool *r_is_merged_icon) { - TreeElement *child_te = static_cast(parent_te->subtree.first); - - while (child_te) { - const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend); - if ((child_te->flag & TE_ICONROW) && over_element) { - return child_te; + for (TreeElement &child_te : parent_te->child_elements) { + const bool over_element = (view_co_x > child_te.xs) && (view_co_x < child_te.xend); + if ((child_te.flag & TE_ICONROW) && over_element) { + return &child_te; } - if ((child_te->flag & TE_ICONROW_MERGED) && over_element) { + if ((child_te.flag & TE_ICONROW_MERGED) && over_element) { if (r_is_merged_icon) { *r_is_merged_icon = true; } - return child_te; + return &child_te; } TreeElement *te = outliner_find_item_at_x_in_row_recursive( - child_te, view_co_x, r_is_merged_icon); - if (te != child_te) { + &child_te, view_co_x, r_is_merged_icon); + if (te != &child_te) { return te; } - - child_te = child_te->next; } /* return parent if no child is hovered */ - return (TreeElement *)parent_te; + return parent_te; } TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner, diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index 76b7197b86a..d6cdf80779f 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -39,6 +39,10 @@ namespace blender::ed::outliner { +SpaceOutliner_Runtime::SpaceOutliner_Runtime() : root_elements() +{ +} + SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/) : tree_display(nullptr), tree_hash(nullptr) { @@ -345,7 +349,6 @@ static void outliner_free(SpaceLink *sl) { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - outliner_free_tree(&space_outliner->tree); if (space_outliner->treestore) { BLI_mempool_destroy(space_outliner->treestore); } diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc index 199c80f021a..448df9c1e7d 100644 --- a/source/blender/editors/space_outliner/tree/common.cc +++ b/source/blender/editors/space_outliner/tree/common.cc @@ -36,25 +36,26 @@ const char *outliner_idcode_to_plural(short idcode) /** \} */ -void outliner_make_object_parent_hierarchy(ListBase *lb) +void outliner_make_object_parent_hierarchy(SubTree &subtree) { /* build hierarchy */ /* XXX also, set extents here... */ - TreeElement *te = static_cast(lb->first); - while (te) { - TreeElement *ten = te->next; - TreeStoreElem *tselem = TREESTORE(te); - - if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { - Object *ob = (Object *)tselem->id; - if (ob->parent && ob->parent->id.newid) { - BLI_remlink(lb, te); - TreeElement *tep = (TreeElement *)ob->parent->id.newid; - BLI_addtail(&tep->subtree, te); - te->parent = tep; - } + for (TreeElement &te : subtree) { + TreeStoreElem *tselem = TREESTORE(&te); + + if ((tselem->type != TSE_SOME_ID) || te.idcode != ID_OB) { + continue; + } + + Object *ob = (Object *)tselem->id; + if (!ob->parent || !ob->parent->id.newid) { + continue; } - te = ten; + + TreeElement *new_parent = reinterpret_cast(ob->parent->id.newid); + + std::unique_ptr floating_te = subtree.remove(te); + new_parent->child_elements.add_back(std::move(floating_te)); } } diff --git a/source/blender/editors/space_outliner/tree/common.hh b/source/blender/editors/space_outliner/tree/common.hh index ba2d1c3fab6..286e81c4a0c 100644 --- a/source/blender/editors/space_outliner/tree/common.hh +++ b/source/blender/editors/space_outliner/tree/common.hh @@ -10,9 +10,11 @@ struct ListBase; namespace blender::ed::outliner { +class SubTree; + const char *outliner_idcode_to_plural(short idcode); -void outliner_make_object_parent_hierarchy(ListBase *lb); +void outliner_make_object_parent_hierarchy(SubTree &subtree); bool outliner_animdata_test(const struct AnimData *adt); } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index 295eeb59eaa..31e35ad0ed8 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -34,6 +34,7 @@ struct ViewLayer; namespace blender::ed::outliner { +class SubTree; struct TreeElement; class TreeElementID; @@ -73,7 +74,7 @@ class AbstractTreeDisplay { * Build a tree for this display mode with the Blender context data given in \a source_data and * the view settings in \a space_outliner. */ - virtual ListBase buildTree(const TreeSourceData &source_data) = 0; + virtual SubTree buildTree(const TreeSourceData &source_data) = 0; /** * Define if the display mode should be allowed to show a mode column on the left. This column @@ -111,14 +112,14 @@ class TreeDisplayViewLayer final : public AbstractTreeDisplay { public: TreeDisplayViewLayer(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; bool supportsModeColumn() const override; private: - void add_view_layer(Scene &, ListBase &, TreeElement *); - void add_layer_collections_recursive(ListBase &, ListBase &, TreeElement &); - void add_layer_collection_objects(ListBase &, LayerCollection &, TreeElement &); + void add_view_layer(Scene &, SubTree &); + void add_layer_collections_recursive(ListBase &, TreeElement &); + void add_layer_collection_objects(LayerCollection &, TreeElement &); void add_layer_collection_objects_children(TreeElement &); }; @@ -132,10 +133,10 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay { public: TreeDisplayLibraries(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; private: - TreeElement *add_library_contents(Main &, ListBase &, Library *); + TreeElement *add_library_contents(Main &, SubTree &, Library *); bool library_id_filter_poll(const Library *lib, ID *id) const; short id_filter_get() const; }; @@ -150,10 +151,10 @@ class TreeDisplayOverrideLibraryProperties final : public AbstractTreeDisplay { public: TreeDisplayOverrideLibraryProperties(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; private: - ListBase add_library_contents(Main &); + SubTree add_library_contents(Main &); short id_filter_get() const; }; @@ -164,14 +165,14 @@ class TreeDisplayOverrideLibraryHierarchies final : public AbstractTreeDisplay { public: TreeDisplayOverrideLibraryHierarchies(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; bool is_lazy_built() const override; private: - ListBase build_hierarchy_for_lib_or_main(Main *bmain, - TreeElement &parent_te, - Library *lib = nullptr); + void build_hierarchy_for_lib_or_main(Main *bmain, + TreeElement &parent_te, + Library *lib = nullptr); }; /* -------------------------------------------------------------------- */ @@ -190,7 +191,7 @@ class TreeDisplaySequencer final : public AbstractTreeDisplay { public: TreeDisplaySequencer(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; private: TreeElement *add_sequencer_contents() const; @@ -211,7 +212,7 @@ class TreeDisplayIDOrphans final : public AbstractTreeDisplay { public: TreeDisplayIDOrphans(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; private: bool datablock_has_orphans(ListBase &) const; @@ -227,7 +228,7 @@ class TreeDisplayScenes final : public AbstractTreeDisplay { public: TreeDisplayScenes(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; bool supportsModeColumn() const override; }; @@ -242,7 +243,7 @@ class TreeDisplayDataAPI final : public AbstractTreeDisplay { public: TreeDisplayDataAPI(SpaceOutliner &space_outliner); - ListBase buildTree(const TreeSourceData &source_data) override; + SubTree buildTree(const TreeSourceData &source_data) override; bool is_lazy_built() const override; }; diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc index 3d9b927fbf1..2206eda2c23 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -22,15 +22,15 @@ TreeDisplayDataAPI::TreeDisplayDataAPI(SpaceOutliner &space_outliner) { } -ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree tree; PointerRNA mainptr; RNA_main_pointer_create(source_data.bmain, &mainptr); TreeElement *te = outliner_add_element( - &space_outliner_, &tree, (void *)&mainptr, nullptr, TSE_RNA_STRUCT, -1); + &space_outliner_, (void *)&mainptr, tree, TSE_RNA_STRUCT, -1); /* On first view open parent data elements */ const int show_opened = !space_outliner_.treestore || diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index 405f1dd73f4..d8268080974 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -29,9 +29,9 @@ TreeDisplayLibraries::TreeDisplayLibraries(SpaceOutliner &space_outliner) { } -ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree tree; { /* current file first - mainvar provides tselem with unique pointer - not used */ @@ -56,13 +56,13 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) } /* make hierarchy */ - for (TreeElement *ten : List(tree)) { - if (ten == tree.first) { + for (TreeElement &ten : tree) { + if (&ten == &*tree.begin()) { /* First item is main, skip. */ continue; } - TreeStoreElem *tselem = TREESTORE(ten); + TreeStoreElem *tselem = TREESTORE(&ten); Library *lib = (Library *)tselem->id; BLI_assert(!lib || (GS(lib->id.name) == ID_LI)); if (!lib || !lib->parent) { @@ -73,16 +73,12 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) if (tselem->id->tag & LIB_TAG_INDIRECT) { /* Only remove from 'first level' if lib is not also directly used. */ - BLI_remlink(&tree, ten); - BLI_addtail(&parent->subtree, ten); - ten->parent = parent; + std::unique_ptr ten_uptr = tree.remove(ten); + parent->child_elements.add_back(std::move(ten_uptr)); } else { /* Else, make a new copy of the libtree for our parent. */ - TreeElement *dupten = add_library_contents(*source_data.bmain, parent->subtree, lib); - if (dupten) { - dupten->parent = parent; - } + add_library_contents(*source_data.bmain, parent->child_elements, lib); } } /* restore newid pointers */ @@ -93,7 +89,9 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) return tree; } -TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib) +TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, + SubTree &subtree, + Library *lib) { const short filter_id_type = id_filter_get(); @@ -135,10 +133,10 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase if (!tenlib) { /* Create library tree element on demand, depending if there are any data-blocks. */ if (lib) { - tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0); + tenlib = outliner_add_element(&space_outliner_, lib, subtree, TSE_SOME_ID, 0); } else { - tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); + tenlib = outliner_add_element(&space_outliner_, &mainvar, subtree, TSE_ID_BASE, 0); tenlib->name = IFACE_("Current File"); } } @@ -151,15 +149,14 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase ten = tenlib; } else { - ten = outliner_add_element( - &space_outliner_, &tenlib->subtree, lib, nullptr, TSE_ID_BASE, a); + ten = outliner_add_element(&space_outliner_, lib, subtree, TSE_ID_BASE, a); ten->directdata = lbarray[a]; ten->name = outliner_idcode_to_plural(GS(id->name)); } for (ID *id : List(lbarray[a])) { if (library_id_filter_poll(lib, id)) { - outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0); + outliner_add_element(&space_outliner_, id, ten, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index d5ecfd4edf3..d7885bb1aa6 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -27,9 +27,9 @@ TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner) { } -ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree tree; ListBase *lbarray[INDEX_ID_MAX]; short filter_id_type = (space_outliner_.filter & SO_FILTER_ID_TYPE) ? space_outliner_.filter_id_type : @@ -56,7 +56,7 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) TreeElement *te = nullptr; if (!filter_id_type) { ID *id = (ID *)lbarray[a]->first; - te = outliner_add_element(&space_outliner_, &tree, lbarray[a], nullptr, TSE_ID_BASE, 0); + te = outliner_add_element(&space_outliner_, lbarray[a], tree, TSE_ID_BASE, 0); te->directdata = lbarray[a]; te->name = outliner_idcode_to_plural(GS(id->name)); } @@ -64,8 +64,7 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) /* Add the orphaned data-blocks - these will not be added with any subtrees attached. */ for (ID *id : List(lbarray[a])) { if (ID_REAL_USERS(id) <= 0) { - outliner_add_element( - &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0); + outliner_add_element(&space_outliner_, id, te ? te->child_elements : tree, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc index fa4479d0d9d..679627d6518 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc @@ -33,13 +33,13 @@ TreeDisplayOverrideLibraryHierarchies::TreeDisplayOverrideLibraryHierarchies( { } -ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree tree; /* First step: Build "Current File" hierarchy. */ TreeElement *current_file_te = outliner_add_element( - &space_outliner_, &tree, source_data.bmain, nullptr, TSE_ID_BASE, -1); + &space_outliner_, source_data.bmain, tree, TSE_ID_BASE, -1); current_file_te->name = IFACE_("Current File"); AbstractTreeElement::uncollapse_by_default(current_file_te); { @@ -48,7 +48,7 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData & /* Add dummy child if there's nothing to display. */ if (BLI_listbase_is_empty(¤t_file_te->subtree)) { TreeElement *dummy_te = outliner_add_element( - &space_outliner_, ¤t_file_te->subtree, nullptr, current_file_te, TSE_ID_BASE, 0); + &space_outliner_, nullptr, current_file_te, TSE_ID_BASE, 0); dummy_te->name = IFACE_("No Library Overrides"); } } @@ -56,19 +56,18 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData & /* Second step: Build hierarchies for external libraries. */ for (Library *lib = (Library *)source_data.bmain->libraries.first; lib; lib = (Library *)lib->id.next) { - TreeElement *tenlib = outliner_add_element( - &space_outliner_, &tree, lib, nullptr, TSE_SOME_ID, 0); + TreeElement *tenlib = outliner_add_element(&space_outliner_, lib, tree, TSE_SOME_ID, 0); build_hierarchy_for_lib_or_main(source_data.bmain, *tenlib, lib); } /* Remove top level library elements again that don't contain any overrides. */ - LISTBASE_FOREACH_MUTABLE (TreeElement *, top_level_te, &tree) { - if (top_level_te == current_file_te) { + for (TreeElement &top_level_te : tree) { + if (&top_level_te == current_file_te) { continue; } - if (BLI_listbase_is_empty(&top_level_te->subtree)) { - outliner_free_tree_element(top_level_te, &tree); + if (top_level_te.child_elements.is_empty()) { + tree.remove(top_level_te); } } @@ -115,11 +114,10 @@ class OverrideIDHierarchyBuilder { TreeElement &te_to_expand); }; -ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main( - Main *bmain, TreeElement &parent_te, Library *lib) +void TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(Main *bmain, + TreeElement &parent_te, + Library *lib) { - ListBase tree = {nullptr}; - /* Ensure #Main.relations contains the latest mapping of relations. Must be freed before * returning. */ BKE_main_relations_create(bmain, 0); @@ -141,26 +139,20 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main( } TreeElement *new_base_te = id_base_te_map.lookup_or_add_cb(GS(iter_id->name), [&]() { - TreeElement *new_te = outliner_add_element(&space_outliner_, - &parent_te.subtree, - lib ? (void *)lib : bmain, - &parent_te, - TSE_ID_BASE, - base_index++); + TreeElement *new_te = outliner_add_element( + &space_outliner_, lib ? (void *)lib : bmain, &parent_te, TSE_ID_BASE, base_index++); new_te->name = outliner_idcode_to_plural(GS(iter_id->name)); return new_te; }); TreeElement *new_id_te = outliner_add_element( - &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false); + &space_outliner_, iter_id, new_base_te, TSE_SOME_ID, 0, false); builder.build_hierarchy_for_ID(*iter_id, *new_id_te); } FOREACH_MAIN_ID_END; BKE_main_relations_free(bmain); - - return tree; } void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id, @@ -220,7 +212,7 @@ void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &pare } TreeElement *new_te = outliner_add_element( - &space_outliner_, &te_to_expand.subtree, &id, &te_to_expand, TSE_SOME_ID, 0, false); + &space_outliner_, &id, &te_to_expand, TSE_SOME_ID, 0, false); build_data.sibling_ids.add(&id); diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_properties.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_properties.cc index 5713a4a6a1f..1cd946f152e 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library_properties.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_properties.cc @@ -31,12 +31,12 @@ TreeDisplayOverrideLibraryProperties::TreeDisplayOverrideLibraryProperties( { } -ListBase TreeDisplayOverrideLibraryProperties::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayOverrideLibraryProperties::buildTree(const TreeSourceData &source_data) { - ListBase tree = add_library_contents(*source_data.bmain); + SubTree tree = add_library_contents(*source_data.bmain); - for (TreeElement *top_level_te : List(tree)) { - TreeStoreElem *tselem = TREESTORE(top_level_te); + for (TreeElement &top_level_te : tree) { + TreeStoreElem *tselem = TREESTORE(&top_level_te); if (!tselem->used) { tselem->flag &= ~TSE_CLOSED; } @@ -45,9 +45,9 @@ ListBase TreeDisplayOverrideLibraryProperties::buildTree(const TreeSourceData &s return tree; } -ListBase TreeDisplayOverrideLibraryProperties::add_library_contents(Main &mainvar) +SubTree TreeDisplayOverrideLibraryProperties::add_library_contents(Main &mainvar) { - ListBase tree = {nullptr}; + SubTree tree; const short filter_id_type = id_filter_get(); @@ -82,33 +82,32 @@ ListBase TreeDisplayOverrideLibraryProperties::add_library_contents(Main &mainva /* Create data-block list parent element on demand. */ TreeElement *id_base_te = nullptr; - ListBase *lb_to_expand = &tree; + SubTree *subtree_to_expand = &tree; if (!filter_id_type) { - id_base_te = outliner_add_element( - &space_outliner_, &tree, lbarray[a], nullptr, TSE_ID_BASE, 0); + id_base_te = outliner_add_element(&space_outliner_, lbarray[a], tree, TSE_ID_BASE, 0); id_base_te->directdata = lbarray[a]; id_base_te->name = outliner_idcode_to_plural(GS(id->name)); - lb_to_expand = &id_base_te->subtree; + subtree_to_expand = &id_base_te->child_elements; } for (ID *id : List(lbarray[a])) { if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && !ID_IS_LINKED(id)) { TreeElement *override_tree_element = outliner_add_element( - &space_outliner_, lb_to_expand, id, id_base_te, TSE_LIBRARY_OVERRIDE_BASE, 0); + &space_outliner_, id, id_base_te, TSE_LIBRARY_OVERRIDE_BASE, 0); - if (BLI_listbase_is_empty(&override_tree_element->subtree)) { - outliner_free_tree_element(override_tree_element, lb_to_expand); + if (override_tree_element->child_elements.is_empty()) { + subtree_to_expand->remove(*override_tree_element); } } } } /* Remove ID base elements that turn out to be empty. */ - LISTBASE_FOREACH_MUTABLE (TreeElement *, te, &tree) { - if (BLI_listbase_is_empty(&te->subtree)) { - outliner_free_tree_element(te, &tree); + for (TreeElement &te : tree) { + if (te.child_elements.is_empty()) { + tree.remove(te); } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index 6b1de7f8b95..671a2b8c113 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -31,17 +31,16 @@ bool TreeDisplayScenes::supportsModeColumn() const return true; } -ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayScenes::buildTree(const TreeSourceData &source_data) { /* On first view we open scenes. */ const int show_opened = !space_outliner_.treestore || !BLI_mempool_len(space_outliner_.treestore); - ListBase tree = {nullptr}; + SubTree tree; for (ID *id : List(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast(id); - TreeElement *te = outliner_add_element( - &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0); + TreeElement *te = outliner_add_element(&space_outliner_, scene, tree, TSE_SOME_ID, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ @@ -49,7 +48,7 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) tselem->flag &= ~TSE_CLOSED; } - outliner_make_object_parent_hierarchy(&te->subtree); + outliner_make_object_parent_hierarchy(te->child_elements); } return tree; diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc index c2739d876f4..530ce40bae7 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc @@ -28,9 +28,9 @@ TreeDisplaySequencer::TreeDisplaySequencer(SpaceOutliner &space_outliner) { } -ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree tree; Editing *ed = SEQ_editing_get(source_data.scene); if (ed == nullptr) { @@ -40,11 +40,10 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) for (Sequence *seq : List(ed->seqbasep)) { SequenceAddOp op = need_add_seq_dup(seq); if (op == SEQUENCE_DUPLICATE_NONE) { - outliner_add_element(&space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE, 0); + outliner_add_element(&space_outliner_, seq, tree, TSE_SEQUENCE, 0); } else if (op == SEQUENCE_DUPLICATE_ADD) { - TreeElement *te = outliner_add_element( - &space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE_DUP, 0); + TreeElement *te = outliner_add_element(&space_outliner_, seq, tree, TSE_SEQUENCE_DUP, 0); add_seq_dup(seq, te, 0); } } @@ -101,7 +100,7 @@ void TreeDisplaySequencer::add_seq_dup(Sequence *seq, TreeElement *te, short ind } if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - outliner_add_element(&space_outliner_, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); + outliner_add_element(&space_outliner_, (void *)p, te, TSE_SEQUENCE, index); } p = p->next; } diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index c8869d90eca..cbaba863950 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -60,9 +60,9 @@ bool TreeDisplayViewLayer::supportsModeColumn() const return true; } -ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) +SubTree TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) { - ListBase tree = {nullptr}; + SubTree subtree; Scene *scene = source_data.scene; show_objects_ = !(space_outliner_.filter & SO_FILTER_NO_OBJECT); @@ -74,23 +74,23 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) continue; } - add_view_layer(*scene, tree, (TreeElement *)nullptr); + add_view_layer(*scene, subtree); } else { TreeElement &te_view_layer = *outliner_add_element( - &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0); + &space_outliner_, scene, subtree, TSE_R_LAYER, 0); TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED; te_view_layer.name = view_layer->name; te_view_layer.directdata = view_layer; - add_view_layer(*scene, te_view_layer.subtree, &te_view_layer); + add_view_layer(*scene, te_view_layer.child_elements); } } - return tree; + return subtree; } -void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElement *parent) +void TreeDisplayViewLayer::add_view_layer(Scene &scene, SubTree &subtree) { const bool show_children = (space_outliner_.filter & SO_FILTER_NO_CHILDREN) == 0; @@ -98,18 +98,18 @@ void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElem /* Show objects in the view layer. */ for (Base *base : List(view_layer_->object_bases)) { TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, parent, TSE_SOME_ID, 0); + &space_outliner_, base->object, subtree, TSE_SOME_ID, 0); te_object->directdata = base; } if (show_children) { - outliner_make_object_parent_hierarchy(&tree); + outliner_make_object_parent_hierarchy(subtree); } } else { /* Show collections in the view layer. */ TreeElement &ten = *outliner_add_element( - &space_outliner_, &tree, &scene, parent, TSE_VIEW_COLLECTION_BASE, 0); + &space_outliner_, &scene, subtree, TSE_VIEW_COLLECTION_BASE, 0); ten.name = IFACE_("Scene Collection"); TREESTORE(&ten)->flag &= ~TSE_CLOSED; @@ -119,9 +119,9 @@ void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElem return; } - add_layer_collections_recursive(ten.subtree, lc->layer_collections, ten); + add_layer_collections_recursive(lc->layer_collections, ten); if (show_objects_) { - add_layer_collection_objects(ten.subtree, *lc, ten); + add_layer_collection_objects(*lc, ten); } if (show_children) { add_layer_collection_objects_children(ten); @@ -129,8 +129,7 @@ void TreeDisplayViewLayer::add_view_layer(Scene &scene, ListBase &tree, TreeElem } } -void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree, - ListBase &layer_collections, +void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &layer_collections, TreeElement &parent_ten) { for (LayerCollection *lc : List(layer_collections)) { @@ -142,8 +141,7 @@ void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree, } else { ID *id = &lc->collection->id; - ten = outliner_add_element( - &space_outliner_, &tree, id, &parent_ten, TSE_LAYER_COLLECTION, 0); + ten = outliner_add_element(&space_outliner_, id, &parent_ten, TSE_LAYER_COLLECTION, 0); ten->name = id->name + 2; ten->directdata = lc; @@ -155,21 +153,19 @@ void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree, } } - add_layer_collections_recursive(ten->subtree, lc->layer_collections, *ten); + add_layer_collections_recursive(lc->layer_collections, *ten); if (!exclude && show_objects_) { - add_layer_collection_objects(ten->subtree, *lc, *ten); + add_layer_collection_objects(*lc, *ten); } } } -void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree, - LayerCollection &lc, - TreeElement &ten) +void TreeDisplayViewLayer::add_layer_collection_objects(LayerCollection &lc, TreeElement &ten) { for (CollectionObject *cob : List(lc.collection->gobject)) { Base *base = BKE_view_layer_base_find(view_layer_, cob->ob); TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0); + &space_outliner_, base->object, &ten, TSE_SOME_ID, 0); te_object->directdata = base; } } @@ -261,9 +257,10 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() for (TreeElement *child_ob_tree_element : child_ob_tree_elements) { if (child_ob_tree_element->parent == parent_ob_collection_tree_element) { /* Move from the collection subtree into the parent object subtree. */ - BLI_remlink(&parent_ob_collection_tree_element->subtree, child_ob_tree_element); - BLI_addtail(&parent_ob_tree_element->subtree, child_ob_tree_element); - child_ob_tree_element->parent = parent_ob_tree_element; + std::unique_ptr removed_te = + parent_ob_collection_tree_element->child_elements.remove(*child_ob_tree_element); + parent_ob_tree_element->child_elements.add_back(std::move(removed_te)); + found = true; break; } @@ -272,13 +269,8 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() if (!found) { /* We add the child in the tree even if it is not in the collection. * We don't expand its sub-tree though, to make it less prominent. */ - TreeElement *child_ob_tree_element = outliner_add_element(&outliner_, - &parent_ob_tree_element->subtree, - child, - parent_ob_tree_element, - TSE_SOME_ID, - 0, - false); + TreeElement *child_ob_tree_element = outliner_add_element( + &outliner_, child, parent_ob_tree_element, TSE_SOME_ID, 0, false); child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION; child_ob_tree_elements.append(child_ob_tree_element); } diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 4a540c3ce87..4b85784d2ae 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -146,4 +146,75 @@ void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner tree_element.expand(space_outliner); } +/* -------------------------------------------------------------------- */ + +SubTree::SubTree(TreeElement &parent) : parent_(&parent) +{ +} + +SubTree::SubTree(SpaceOutliner_Runtime &) : parent_(nullptr) +{ +} + +void SubTree::add_back(std::unique_ptr element) +{ + element->parent = parent_; + /* TODO is this the right place for this? */ + element->child_elements.parent_ = element.get(); + elements_.push_back(std::move(element)); +} + +void SubTree::insert_before(Iterator pos, std::unique_ptr element) +{ + element->parent = parent_; + elements_.insert(pos.iter_, std::move(element)); +} + +std::unique_ptr SubTree::remove(TreeElement &element) +{ + std::unique_ptr element_uptr = nullptr; + /* TODO doesn't free element entirely yet, #TreeElement.name may need freeing! See + * #outliner_free_tree_element(). */ + + for (decltype(elements_)::iterator iter = elements_.begin(); iter != elements_.end(); ++iter) { + if (iter->get() == &element) { + element_uptr = std::move(*iter); + elements_.erase(iter); + break; + } + } + BLI_assert(!has_child(element)); + + if (element_uptr) { + element_uptr->parent = nullptr; + } + return element_uptr; +} + +void SubTree::clear() +{ + elements_.clear(); + /* No need to clear the parent pointer, elements get destructed entirely anyway. */ +} + +bool SubTree::has_child(const TreeElement &needle) const +{ + for (const TreeElement &te : *this) { + if (&te == &needle) { + return true; + } + } + return false; +} + +bool SubTree::is_empty() const +{ + return elements_.empty(); +} + +TreeElement *SubTree::parent() const +{ + return parent_; +} + } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 1b145a48daa..71f64cfe610 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -18,6 +18,7 @@ struct SpaceOutliner; namespace blender::ed::outliner { struct TreeElement; +class SubTree; /* -------------------------------------------------------------------- */ /* Tree-Display Interface */ @@ -114,21 +115,28 @@ class AbstractTreeElement { * TODO: this function needs to be split up! It's getting a bit too large... * * \note "ID" is not always a real ID. - * \note If child items are only added to the tree if the item is open, - * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). + * \note If child items are only added to the tree if the item is open, the `TSE_` type _must_ be + * added to #outliner_element_needs_rebuild_on_open_change(). * + * \param parent: The parent element to add the new element to. If this is null, the new element + * will be added to the root level of the tree. * \param expand: If true, the element may add its own sub-tree. E.g. objects will list their * animation data, object data, constraints, modifiers, ... This often adds visual * noise, and can be expensive to add in big scenes. So prefer setting this to * false. */ -struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, - ListBase *lb, - void *idv, - struct TreeElement *parent, - short type, - short index, - const bool expand = true); +TreeElement *outliner_add_element(SpaceOutliner *space_outliner, + void *idv, + TreeElement *parent, + short type, + short index, + const bool expand = true); +TreeElement *outliner_add_element(SpaceOutliner *space_outliner, + void *idv, + SubTree &subtree, + short type, + short index, + const bool expand = true); void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc index bb514cf6f3c..20f48e2421b 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -30,8 +30,7 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, AnimData &anim_ void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const { /* Animation data-block itself. */ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0); + outliner_add_element(&space_outliner, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0); expand_drivers(space_outliner); expand_NLA_tracks(space_outliner); @@ -42,8 +41,7 @@ void TreeElementAnimData::expand_drivers(SpaceOutliner &space_outliner) const if (BLI_listbase_is_empty(&anim_data_.drivers)) { return; } - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &anim_data_, &legacy_te_, TSE_DRIVER_BASE, 0); + outliner_add_element(&space_outliner, &anim_data_, &legacy_te_, TSE_DRIVER_BASE, 0); } void TreeElementAnimData::expand_NLA_tracks(SpaceOutliner &space_outliner) const @@ -51,7 +49,7 @@ void TreeElementAnimData::expand_NLA_tracks(SpaceOutliner &space_outliner) const if (BLI_listbase_is_empty(&anim_data_.nla_tracks)) { return; } - outliner_add_element(&space_outliner, &legacy_te_.subtree, &anim_data_, &legacy_te_, TSE_NLA, 0); + outliner_add_element(&space_outliner, &anim_data_, &legacy_te_, TSE_NLA, 0); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc index f8072d2814d..acd75fefff3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_driver.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc @@ -40,8 +40,7 @@ void TreeElementDriverBase::expand(SpaceOutliner &space_outliner) const DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { if (lastadded != dtar->id) { /* XXX this lastadded check is rather lame, and also fails quite badly... */ - outliner_add_element( - &space_outliner, &legacy_te_.subtree, dtar->id, &legacy_te_, TSE_LINKED_OB, 0); + outliner_add_element(&space_outliner, dtar->id, &legacy_te_, TSE_LINKED_OB, 0); lastadded = dtar->id; } } diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index 86f5fd4eff5..78f734a5579 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -107,8 +107,7 @@ void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner, const AnimData *anim_data) const { if (outliner_animdata_test(anim_data)) { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_ANIM_DATA, 0); + outliner_add_element(&space_outliner, &id_, &legacy_te_, TSE_ANIM_DATA, 0); } } diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc index 328c19c56fd..753de08c72a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc @@ -36,26 +36,22 @@ void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); + outliner_add_element(&space_outliner, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); } void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0); + outliner_add_element(&space_outliner, scene_.world, &legacy_te_, TSE_SOME_ID, 0); } void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); + outliner_add_element(&space_outliner, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); } void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); + outliner_add_element(&space_outliner, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc index df19b2e8f4b..75ae4d0744b 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc @@ -30,7 +30,7 @@ void TreeElementNLA::expand(SpaceOutliner &space_outliner) const { int a = 0; for (NlaTrack *nlt : ListBaseWrapper(anim_data_.nla_tracks)) { - outliner_add_element(&space_outliner, &legacy_te_.subtree, nlt, &legacy_te_, TSE_NLA_TRACK, a); + outliner_add_element(&space_outliner, nlt, &legacy_te_, TSE_NLA_TRACK, a); a++; } } @@ -48,8 +48,7 @@ void TreeElementNLATrack::expand(SpaceOutliner &space_outliner) const { int a = 0; for (NlaStrip *strip : ListBaseWrapper(track_.strips)) { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, strip->act, &legacy_te_, TSE_NLA_ACTION, a); + outliner_add_element(&space_outliner, strip->act, &legacy_te_, TSE_NLA_ACTION, a); a++; } } diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc index 11067d37966..f4684d89d45 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc @@ -353,12 +353,8 @@ void OverrideRNAPathTreeBuilder::build_path(TreeElement &parent, * values), so the element may already be present. At this point they are displayed as a single * property in the tree, so don't add it multiple times here. */ else if (!path_te_map.contains(override_data.override_property.rna_path)) { - outliner_add_element(&space_outliner_, - &te_to_expand->subtree, - &override_data, - te_to_expand, - TSE_LIBRARY_OVERRIDE, - index++); + outliner_add_element( + &space_outliner_, &override_data, te_to_expand, TSE_LIBRARY_OVERRIDE, index++); } MEM_delete(elem_path); @@ -403,7 +399,6 @@ void OverrideRNAPathTreeBuilder::ensure_entire_collection( override_op_data.operation = item_operation; current_te = outliner_add_element(&space_outliner_, - &te_to_expand.subtree, /* Element will store a copy. */ &override_op_data, &te_to_expand, @@ -446,7 +441,6 @@ TreeElement &OverrideRNAPathTreeBuilder::ensure_label_element_for_prop( { return *path_te_map.lookup_or_add_cb(elem_path, [&]() { TreeElement *new_te = outliner_add_element(&space_outliner_, - &parent.subtree, (void *)RNA_property_ui_name(&prop), &parent, TSE_GENERIC_LABEL, @@ -469,7 +463,6 @@ TreeElement &OverrideRNAPathTreeBuilder::ensure_label_element_for_ptr(TreeElemen TreeElement *new_te = outliner_add_element( &space_outliner_, - &parent.subtree, (void *)(dyn_name ? dyn_name : RNA_struct_ui_name(ptr.type)), &parent, TSE_GENERIC_LABEL, diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc index 9e1f22b49d6..9a0563f36fa 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -118,8 +118,7 @@ void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const PointerRNA propptr; RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr); if (!(RNA_property_flag(static_cast(propptr.data)) & PROP_HIDDEN)) { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index); + outliner_add_element(&space_outliner, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index); } } } @@ -168,8 +167,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const if (pptr.data) { if (TSELEM_OPEN(&tselem, &space_outliner)) { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1); + outliner_add_element(&space_outliner, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1); } else { legacy_te_.flag |= TE_PRETEND_HAS_CHILDREN; @@ -184,8 +182,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const for (int index = 0; index < tot; index++) { PointerRNA pptr; RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr); - outliner_add_element( - &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, index); + outliner_add_element(&space_outliner, &pptr, &legacy_te_, TSE_RNA_STRUCT, index); } } else if (tot) { @@ -198,12 +195,7 @@ void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const if (TSELEM_OPEN(&tselem, &space_outliner)) { for (int index = 0; index < tot; index++) { - outliner_add_element(&space_outliner, - &legacy_te_.subtree, - &rna_ptr, - &legacy_te_, - TSE_RNA_ARRAY_ELEM, - index); + outliner_add_element(&space_outliner, &rna_ptr, &legacy_te_, TSE_RNA_ARRAY_ELEM, index); } } else if (tot) { diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc index b47707e8891..0f6b9363bf9 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc @@ -29,10 +29,10 @@ TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const { FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) { - outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0); + outliner_add_element(&space_outliner, ob, &legacy_te_, TSE_SOME_ID, 0); } FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&legacy_te_.subtree); + outliner_make_object_parent_hierarchy(legacy_te_.child_elements); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.cc b/source/blender/editors/space_outliner/tree/tree_element_seq.cc index 550a72d246d..dbe587075f8 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_seq.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_seq.cc @@ -45,13 +45,11 @@ void TreeElementSequence::expand(SpaceOutliner &space_outliner) const if (sequence_.type == SEQ_TYPE_META) { LISTBASE_FOREACH (Sequence *, child, &sequence_.seqbase) { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, child, &legacy_te_, TSE_SEQUENCE, 0); + outliner_add_element(&space_outliner, child, &legacy_te_, TSE_SEQUENCE, 0); } } else { - outliner_add_element( - &space_outliner, &legacy_te_.subtree, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0); + outliner_add_element(&space_outliner, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0); } } diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc index da82854facb..ba11af3110a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc @@ -29,7 +29,7 @@ void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const { for (auto *view_layer : ListBaseWrapper(scene_.view_layers)) { TreeElement *tenlay = outliner_add_element( - &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0); + &space_outliner, &scene_, &legacy_te_, TSE_R_LAYER, 0); tenlay->name = view_layer->name; tenlay->directdata = view_layer; } -- cgit v1.2.3