/* SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup spoutliner */ #include #include #include "DNA_anim_types.h" #include "DNA_listBase.h" #include "DNA_space_types.h" #include "UI_resources.h" #include "BLT_translation.h" #include "tree_element_anim_data.hh" #include "tree_element_collection.hh" #include "tree_element_driver.hh" #include "tree_element_gpencil_layer.hh" #include "tree_element_id.hh" #include "tree_element_label.hh" #include "tree_element_nla.hh" #include "tree_element_overrides.hh" #include "tree_element_rna.hh" #include "tree_element_scene_objects.hh" #include "tree_element_seq.hh" #include "tree_element_view_layer.hh" #include "../outliner_intern.hh" #include "tree_element.hh" namespace blender::ed::outliner { std::unique_ptr AbstractTreeElement::createFromType(const int type, TreeElement &legacy_te, void *idv) { if (idv == nullptr) { return nullptr; } /* * The following calls make an implicit assumption about what data was passed to the `idv` * argument of #outliner_add_element(). The old code does this already, here we just centralize * it as much as possible for now. Would be nice to entirely get rid of that, no more `void *`. * * Once #outliner_add_element() is sufficiently simplified, it should be replaced by a C++ call. * It could take the derived type as template parameter (e.g. #TreeElementAnimData) and use C++ * perfect forwarding to pass any data to the type's constructor. * If general Outliner code wants to access the data, they can query that through the derived * element type then. There's no need for `void *` anymore then. */ switch (type) { case TSE_SOME_ID: return TreeElementID::createFromID(legacy_te, *static_cast(idv)); case TSE_GENERIC_LABEL: return std::make_unique(legacy_te, static_cast(idv)); case TSE_ANIM_DATA: return std::make_unique(legacy_te, *static_cast(idv)->adt); case TSE_DRIVER_BASE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_NLA: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_NLA_TRACK: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_NLA_ACTION: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_GP_LAYER: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_R_LAYER_BASE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_SCENE_COLLECTION_BASE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_SCENE_OBJECTS_BASE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_LIBRARY_OVERRIDE_BASE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_LIBRARY_OVERRIDE: return std::make_unique( legacy_te, *static_cast(idv)); case TSE_LIBRARY_OVERRIDE_OPERATION: return std::make_unique( legacy_te, *static_cast(idv)); case TSE_RNA_STRUCT: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_RNA_PROPERTY: return std::make_unique( legacy_te, *static_cast(idv), legacy_te.index); case TSE_RNA_ARRAY_ELEM: return std::make_unique( legacy_te, *static_cast(idv), legacy_te.index); case TSE_SEQUENCE: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_SEQ_STRIP: return std::make_unique(legacy_te, *static_cast(idv)); case TSE_SEQUENCE_DUP: return std::make_unique(legacy_te, *static_cast(idv)); default: break; } return nullptr; } StringRefNull AbstractTreeElement::getWarning() const { return ""; } std::optional AbstractTreeElement::getIcon() const { return {}; } void AbstractTreeElement::print_path() { std::string path = legacy_te_.name; for (TreeElement *parent = legacy_te_.parent; parent; parent = parent->parent) { path = parent->name + std::string_view("/") + path; } std::cout << path << std::endl; } void AbstractTreeElement::uncollapse_by_default(TreeElement *legacy_te) { if (!TREESTORE(legacy_te)->used) { TREESTORE(legacy_te)->flag &= ~TSE_CLOSED; } } void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner) { /* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common * expanding. Could be done nicer, we could request a small "expander" helper object from the * element type, that the IDs have a more advanced implementation for. */ if (!tree_element.expandPoll(space_outliner)) { return; } 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