diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 1c09ad2d98f..97d2957eed2 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC tree/tree_element_scene_objects.cc tree/tree_element_seq.cc tree/tree_element_view_layer.cc + tree/tree_iterator.cc outliner_intern.hh tree/common.hh @@ -76,6 +77,7 @@ set(SRC tree/tree_element_scene_objects.hh tree/tree_element_seq.hh tree/tree_element_view_layer.hh + tree/tree_iterator.hh ) set(LIB diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc new file mode 100644 index 00000000000..85ff9e6437e --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_space_types.h" + +#include "BLI_listbase.h" + +#include "../outliner_intern.hh" + +#include "tree_iterator.hh" + +namespace blender::ed::outliner::tree_iterator { + +void all(const SpaceOutliner &space_outliner, const VisitorFn visitor) +{ + all_open(space_outliner, space_outliner.tree, visitor); +} + +void all(const ListBase &subtree, const VisitorFn visitor) +{ + LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) { + /* Get needed data out in case element gets freed. */ + const ListBase subtree = element->subtree; + + visitor(element); + /* Don't access element from now on, it may be freed. */ + + all(subtree, visitor); + } +} + +void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor) +{ + all_open(space_outliner, space_outliner.tree, visitor); +} + +void all_open(const SpaceOutliner &space_outliner, + const ListBase &subtree, + const VisitorFn visitor) +{ + LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) { + /* Get needed data out in case element gets freed. */ + const bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner); + const ListBase subtree = element->subtree; + + visitor(element); + /* Don't access element from now on, it may be freed. */ + + if (is_open) { + all_open(space_outliner, subtree, visitor); + } + } +} + +} // namespace blender::ed::outliner::tree_iterator diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh new file mode 100644 index 00000000000..e3b3c90eaad --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "BLI_function_ref.hh" + +struct ListBase; +struct SpaceOutliner; +struct TreeElement; + +namespace blender::ed::outliner { +namespace tree_iterator { + +using VisitorFn = FunctionRef; + +/** + * Preorder (meaning depth-first) traversal of all elements (regardless of collapsed state). + * Freeing the currently visited element in \a visitor is fine. + */ +void all(const SpaceOutliner &space_outliner, VisitorFn visitor); +void all(const ListBase &subtree, VisitorFn visitor); + +/** + * Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree. + * Freeing the currently visited element in \a visitor is fine. + */ +void all_open(const SpaceOutliner &, VisitorFn visitor); +void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor); + +} // namespace tree_iterator +} // namespace blender::ed::outliner