From 2b1b1e699117dfb80094f45329dc5efcf7526d8a Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 24 Aug 2023 14:58:28 +0200 Subject: [PATCH 1/4] Initial tree-view UI for collection tree in sidebar --- scripts/startup/bl_ui/space_view3d.py | 3 +- .../blender/editors/include/UI_interface_c.hh | 2 + .../blender/editors/interface/CMakeLists.txt | 1 + .../interface_template_collection_tree.cc | 162 ++++++++++++++++++ .../editors/interface/views/tree_view.cc | 2 + source/blender/makesrna/intern/rna_ui_api.cc | 4 + 6 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 source/blender/editors/interface/interface_template_collection_tree.cc diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 275a51a3d8a..f6897d12185 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -6092,7 +6092,8 @@ class VIEW3D_PT_collections(Panel): # We pass index 0 here because the index is increased # so the first real index is 1 # And we start with index as 1 because we skip the master collection - self._draw_collection(layout, view_layer, view.use_local_collections, view_layer.layer_collection, 0) + layout.template_collection_tree() + # self._draw_collection(layout, view_layer, view.use_local_collections, view_layer.layer_collection, 0) class VIEW3D_PT_object_type_visibility(Panel): diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 76dac42a2a6..d0f752619b5 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -2583,6 +2583,8 @@ void uiTemplateLightLinkingCollection(uiLayout *layout, PointerRNA *ptr, const c void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C); +void uiTemplateCollectionTree(uiLayout *layout, bContext *C); + /** * \return: A RNA pointer for the operator properties. */ diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 529ecf59127..f91d6024f83 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -67,6 +67,7 @@ set(SRC interface_style.cc interface_template_asset_view.cc interface_template_attribute_search.cc + interface_template_collection_tree.cc interface_template_grease_pencil_layer_tree.cc interface_template_light_linking.cc interface_template_list.cc diff --git a/source/blender/editors/interface/interface_template_collection_tree.cc b/source/blender/editors/interface/interface_template_collection_tree.cc new file mode 100644 index 00000000000..73d8fce3b0e --- /dev/null +++ b/source/blender/editors/interface/interface_template_collection_tree.cc @@ -0,0 +1,162 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edinterface + */ + +#include "DNA_collection_types.h" +#include "DNA_layer_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_layer.h" + +#include "RNA_access.hh" +#include "RNA_prototypes.h" + +#include "UI_tree_view.hh" + +namespace blender::ui { + +class CollectionTreeView : public AbstractTreeView { + Scene &scene_; + ViewLayer &view_layer_; + /** View3D from context, if any. Used for local overrides (local collections toggle). */ + View3D *view3d_ = nullptr; + + bool use_local_collections_ = false; + bool show_viewport_visibility_ = false; + + friend class CollectionTreeViewItem; + + public: + CollectionTreeView(Scene &scene, ViewLayer &view_layer, View3D *view3d) + : scene_(scene), view_layer_(view_layer), view3d_(view3d) + { + } + void build_tree() override; + + void set_use_local_collections(const bool use_local_collections) + { + use_local_collections_ = use_local_collections; + } + void enable_viewport_visibility_toggle() + { + show_viewport_visibility_ = true; + } +}; + +/* ---------------------------------------------------------------------- */ + +class CollectionTreeViewItem : public BasicTreeViewItem { + LayerCollection &collection_; + LayerCollection &parent_collection_; + + public: + CollectionTreeViewItem(LayerCollection &collection, LayerCollection &parent_collection) + : BasicTreeViewItem(collection.collection->id.name + 2), + collection_(collection), + parent_collection_(parent_collection) + { + } + + void add_viewport_visibility_toggle(uiLayout &layout, PointerRNA &collection_ptr) + { + CollectionTreeView &view = static_cast(get_tree_view()); + if (view.use_local_collections_ && view.view3d_) { + const bool visible_in_viewport = + ((view.view3d_->local_collections_uuid & collection_.local_collections_bits) && + !(parent_collection_.runtime_flag & LAYER_COLLECTION_HIDE_VIEWPORT)); + + uiLayoutSetActive(&layout, visible_in_viewport); + + PointerRNA opptr; + uiItemFullO(&layout, + "object.hide_collection", + "", + ICON_HIDE_OFF, + nullptr, + WM_OP_INVOKE_DEFAULT, + UI_ITEM_NONE, + &opptr); + RNA_int_set(&opptr, + "collection_index", + BKE_layer_collection_findindex(&view.view_layer_, &collection_)); + RNA_boolean_set(&opptr, "toggle", true); + } + else { + uiLayoutSetActive(&layout, + parent_collection_.runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER); + uiItemR(&layout, &collection_ptr, "hide_viewport", UI_ITEM_R_COMPACT, "", ICON_HIDE_OFF); + } + } + + void build_row(uiLayout &row) override + { + add_label(row); + + uiLayout *sub = uiLayoutRow(&row, false); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); + CollectionTreeView &view = static_cast(get_tree_view()); + + PointerRNA collection_ptr; + RNA_pointer_create(&view.scene_.id, &RNA_LayerCollection, &collection_, &collection_ptr); + + if (view.show_viewport_visibility_) { + add_viewport_visibility_toggle(*sub, collection_ptr); + } + } +}; + +/* ---------------------------------------------------------------------- */ + +static void add_children_recursive(TreeViewOrItem &parent_item, LayerCollection &parent_collection) +{ + LISTBASE_FOREACH (LayerCollection *, child, &parent_collection.layer_collections) { + if (child->flag & LAYER_COLLECTION_EXCLUDE) { + continue; + } + if (child->collection->flag & COLLECTION_HIDE_VIEWPORT) { + continue; + } + + AbstractTreeViewItem &new_item = parent_item.add_tree_item( + *child, parent_collection); + add_children_recursive(new_item, *child); + } +} + +void CollectionTreeView::build_tree() +{ + LayerCollection &scene_collection = *static_cast( + view_layer_.layer_collections.first); + add_children_recursive(*this, scene_collection); +} + +} // namespace blender::ui + +/* ---------------------------------------------------------------------- */ + +using namespace blender; + +void uiTemplateCollectionTree(uiLayout *layout, bContext *C) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *view3d = CTX_wm_view3d(C); + + uiBlock *block = uiLayoutGetBlock(layout); + + std::unique_ptr collection_view = std::make_unique( + *scene, *view_layer, view3d); + collection_view->set_min_rows(5); + /* TODO: Pass the following as template options? */ + collection_view->set_use_local_collections(view3d && (view3d->flag & V3D_LOCAL_COLLECTIONS)); + collection_view->enable_viewport_visibility_toggle(); + + ui::AbstractTreeView *tree_view = UI_block_add_view( + *block, "Collection Tree View", std::move(collection_view)); + ui::TreeViewBuilder::build_tree_view(*tree_view, *layout); +} diff --git a/source/blender/editors/interface/views/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc index fc33f7bff68..0297c866f18 100644 --- a/source/blender/editors/interface/views/tree_view.cc +++ b/source/blender/editors/interface/views/tree_view.cc @@ -612,6 +612,8 @@ void TreeViewLayoutBuilder::build_row(AbstractTreeViewItem &item) const eUIEmbossType previous_emboss = UI_block_emboss_get(&block_); uiLayout *overlap = uiLayoutOverlap(&prev_layout); + uiLayoutSetPropSep(overlap, false); + uiLayoutSetPropDecorate(overlap, false); if (!item.is_interactive_) { uiLayoutSetActive(overlap, false); diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index 472b4ac5dc0..e7d509786e2 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -2081,6 +2081,10 @@ void RNA_api_ui_layout(StructRNA *srna) "Visualization of a content of a light linking collection"); api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_collection_tree", "uiTemplateCollectionTree"); + RNA_def_function_ui_description(func, "Display the current scene's collection hierarchy"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + func = RNA_def_function( srna, "template_grease_pencil_layer_tree", "uiTemplateGreasePencilLayerTree"); RNA_def_function_ui_description(func, "View of the active grease pencil layer tree"); -- 2.30.2 From bb47ed36aab10054919816a3e913286763a427e4 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 25 Aug 2023 12:56:27 +0200 Subject: [PATCH 2/4] Rename template_collection_tree to template_scene_collection_tree --- scripts/startup/bl_ui/space_view3d.py | 2 +- source/blender/editors/include/UI_interface_c.hh | 2 +- .../editors/interface/interface_template_collection_tree.cc | 6 ++++-- source/blender/makesrna/intern/rna_ui_api.cc | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index f6897d12185..625015d8229 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -6092,7 +6092,7 @@ class VIEW3D_PT_collections(Panel): # We pass index 0 here because the index is increased # so the first real index is 1 # And we start with index as 1 because we skip the master collection - layout.template_collection_tree() + layout.template_scene_collection_tree() # self._draw_collection(layout, view_layer, view.use_local_collections, view_layer.layer_collection, 0) diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index d0f752619b5..90e603311a9 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -2583,7 +2583,7 @@ void uiTemplateLightLinkingCollection(uiLayout *layout, PointerRNA *ptr, const c void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C); -void uiTemplateCollectionTree(uiLayout *layout, bContext *C); +void uiTemplateSceneCollectionTree(uiLayout *layout, bContext *C); /** * \return: A RNA pointer for the operator properties. diff --git a/source/blender/editors/interface/interface_template_collection_tree.cc b/source/blender/editors/interface/interface_template_collection_tree.cc index 73d8fce3b0e..8201727d9bf 100644 --- a/source/blender/editors/interface/interface_template_collection_tree.cc +++ b/source/blender/editors/interface/interface_template_collection_tree.cc @@ -141,10 +141,11 @@ void CollectionTreeView::build_tree() using namespace blender; -void uiTemplateCollectionTree(uiLayout *layout, bContext *C) +void uiTemplateSceneCollectionTree(uiLayout *layout, bContext *C) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + /* May me null if this is not displayed in a 3D view! */ View3D *view3d = CTX_wm_view3d(C); uiBlock *block = uiLayoutGetBlock(layout); @@ -152,7 +153,8 @@ void uiTemplateCollectionTree(uiLayout *layout, bContext *C) std::unique_ptr collection_view = std::make_unique( *scene, *view_layer, view3d); collection_view->set_min_rows(5); - /* TODO: Pass the following as template options? */ + /* These things could be turned into options for the template (or there could be multiple + * templates displaying the tree in different ways). For now keep it entirely context based. */ collection_view->set_use_local_collections(view3d && (view3d->flag & V3D_LOCAL_COLLECTIONS)); collection_view->enable_viewport_visibility_toggle(); diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index c95acfcee01..54408bf8f9d 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -2081,7 +2081,7 @@ void RNA_api_ui_layout(StructRNA *srna) "Visualization of a content of a light linking collection"); api_ui_item_rna_common(func); - func = RNA_def_function(srna, "template_collection_tree", "uiTemplateCollectionTree"); + func = RNA_def_function(srna, "template_scene_collection_tree", "uiTemplateSceneCollectionTree"); RNA_def_function_ui_description(func, "Display the current scene's collection hierarchy"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); -- 2.30.2 From 29efed4200f02d373a6d6a0e00b692d5de85a1aa Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 25 Aug 2023 13:12:40 +0200 Subject: [PATCH 3/4] Sync active tree item with active collection --- .../interface_template_collection_tree.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source/blender/editors/interface/interface_template_collection_tree.cc b/source/blender/editors/interface/interface_template_collection_tree.cc index 8201727d9bf..997a55d0a2d 100644 --- a/source/blender/editors/interface/interface_template_collection_tree.cc +++ b/source/blender/editors/interface/interface_template_collection_tree.cc @@ -16,6 +16,8 @@ #include "RNA_access.hh" #include "RNA_prototypes.h" +#include "WM_api.hh" + #include "UI_tree_view.hh" namespace blender::ui { @@ -62,6 +64,21 @@ class CollectionTreeViewItem : public BasicTreeViewItem { { } + std::optional should_be_active() const override + { + const CollectionTreeView &view = static_cast(get_tree_view()); + return BKE_view_layer_active_collection_get(&view.view_layer_) == &collection_; + } + + void on_activate(bContext &C) override + { + CollectionTreeView &view = static_cast(get_tree_view()); + BKE_layer_collection_activate(&view.view_layer_, &collection_); + /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary + * work when only the active collection changes. */ + WM_event_add_notifier(&C, NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr); + } + void add_viewport_visibility_toggle(uiLayout &layout, PointerRNA &collection_ptr) { CollectionTreeView &view = static_cast(get_tree_view()); -- 2.30.2 From 8cc1a1fe0b45a109e9d8d8cd3581f055a7564740 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 28 Sep 2023 15:58:37 +0200 Subject: [PATCH 4/4] Adapt to changes in main branch --- .../editors/interface/interface_template_collection_tree.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface_template_collection_tree.cc b/source/blender/editors/interface/interface_template_collection_tree.cc index 997a55d0a2d..39afee35c58 100644 --- a/source/blender/editors/interface/interface_template_collection_tree.cc +++ b/source/blender/editors/interface/interface_template_collection_tree.cc @@ -118,8 +118,8 @@ class CollectionTreeViewItem : public BasicTreeViewItem { uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); CollectionTreeView &view = static_cast(get_tree_view()); - PointerRNA collection_ptr; - RNA_pointer_create(&view.scene_.id, &RNA_LayerCollection, &collection_, &collection_ptr); + PointerRNA collection_ptr = RNA_pointer_create( + &view.scene_.id, &RNA_LayerCollection, &collection_); if (view.show_viewport_visibility_) { add_viewport_visibility_toggle(*sub, collection_ptr); -- 2.30.2