[Bf-blender-cvs] [7fcfbba30ed] temp-asset-browser-catalogs-ui: Add and use initial UI Tree-View API

Julian Eisel noreply at git.blender.org
Fri Sep 3 23:33:05 CEST 2021


Commit: 7fcfbba30edd425ce99492041176d8bbac5729a5
Author: Julian Eisel
Date:   Fri Sep 3 23:19:51 2021 +0200
Branches: temp-asset-browser-catalogs-ui
https://developer.blender.org/rB7fcfbba30edd425ce99492041176d8bbac5729a5

Add and use initial UI Tree-View API

This adds a simple to use API to implement custom tree views. This
should make adding tree like layouts much easier & cleaner. Plus, it
should become easier to mange UI state (once I've done some more
additions).
Another goal for this was separating UI code better from the data,
currently we often have to add UI state information to the data (we may
still have to do this in some cases for file writing).

Idea is to let API users implement a custom tree-view class, that
inherits from `uiAbstractTreeView` and implements its `build_tree()`
function to add tree items. Each such item has a custom type, that
defines how its tree row is drawn. For that, another class can be added,
inheriting from `uiAbstractTreeViewItem` and implementing its
`build_row()` function. But this also adds `uiBasicTreeViewItem` which
is just a tree-row with an icon and a label, for convenience. More such
common tree-view item types can be added.

I'm quite happy with how this turned out eventually. This could work!

The resulting UI should look identical to the one before this commit.
Only internals changed (drastically).

===================================================================

M	source/blender/blenkernel/BKE_asset_catalog.hh
M	source/blender/blenkernel/intern/asset_catalog.cc
M	source/blender/editors/include/UI_interface.h
A	source/blender/editors/include/UI_tree_view.hh
M	source/blender/editors/interface/CMakeLists.txt
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_handlers.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_query.c
M	source/blender/editors/interface/interface_widgets.c
A	source/blender/editors/interface/tree_view.cc
M	source/blender/editors/space_file/asset_catalog_tree_view.cc
M	source/blender/editors/util/CMakeLists.txt

===================================================================

diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index cf854b203fd..3b9c9263b08 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -44,6 +44,7 @@ using CatalogFilePath = filesystem::path;
 class AssetCatalog;
 class AssetCatalogDefinitionFile;
 class AssetCatalogTree;
+class AssetCatalogTreeItemIterator;
 
 /* Manages the asset catalogs of a single asset library (i.e. of catalogs defined in a single
  * directory hierarchy). */
@@ -110,11 +111,13 @@ class AssetCatalogTreeItem {
   friend class AssetCatalogTree;
 
  public:
+  /* TODO change name to ChildMap! */
   using ChildSet = std::map<std::string, AssetCatalogTreeItem>;
   using ItemIterFn = FunctionRef<void(const AssetCatalogTreeItem &)>;
 
   AssetCatalogTreeItem(StringRef name, const AssetCatalogTreeItem *parent = nullptr);
 
+  AssetCatalogTreeItemIterator children();
   StringRef get_name() const;
   /** Return the full catalog path, defined as the name of this catalog prefixed by the full
    * catalog path of its parent and a separator. */
@@ -142,16 +145,46 @@ class AssetCatalogTreeItem {
  */
 class AssetCatalogTree {
   friend class AssetCatalogService;
+  using ChildSet = AssetCatalogTreeItem::ChildSet;
 
  public:
   /** Ensure an item representing \a path is in the tree, adding it if necessary. */
   void insert_item(StringRef catalog_path_str);
 
+  AssetCatalogTreeItemIterator children();
   void foreach_item(const AssetCatalogTreeItem::ItemIterFn callback) const;
 
  protected:
   /** Child tree items, ordered by their names. */
-  AssetCatalogTreeItem::ChildSet children_;
+  ChildSet children_;
+};
+
+/* TODO mostly boilerplate code. Is that worth it? Could alternatively expose the ChildSet
+ * directly, and let users iterate over the map and its (key, value) pairs directly. */
+class AssetCatalogTreeItemIterator
+    : public std::iterator<std::forward_iterator_tag, AssetCatalogTreeItem> {
+  /** #AssetCatalogTreeItemIterator is just a wrapper around the child-maps iterator. That is so we
+   * can iterate over the values only of the map's (key, value) pairs. */
+  using WrappedIterator = AssetCatalogTreeItem::ChildSet::iterator;
+
+  WrappedIterator wrapped_iterator_;
+  WrappedIterator wrapped_end_iterator_;
+
+ public:
+  AssetCatalogTreeItemIterator(WrappedIterator wrapped_iterator,
+                               WrappedIterator wrapped_end_iterator);
+
+  AssetCatalogTreeItemIterator begin() const;
+  AssetCatalogTreeItemIterator end() const;
+
+  AssetCatalogTreeItem &operator*() const;
+  AssetCatalogTreeItem *operator->() const;
+
+  AssetCatalogTreeItemIterator &operator++();
+  AssetCatalogTreeItemIterator operator++(int);
+
+  friend bool operator==(AssetCatalogTreeItemIterator a, AssetCatalogTreeItemIterator b);
+  friend bool operator!=(AssetCatalogTreeItemIterator a, AssetCatalogTreeItemIterator b);
 };
 
 /** Keeps track of which catalogs are defined in a certain file on disk.
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index 425f89bc3ca..758be9c28e5 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -246,11 +246,18 @@ std::unique_ptr<AssetCatalogTree> AssetCatalogService::read_into_tree()
   return tree;
 }
 
+/* ---------------------------------------------------------------------- */
+
 AssetCatalogTreeItem::AssetCatalogTreeItem(StringRef name, const AssetCatalogTreeItem *parent)
     : name_(name), parent_(parent)
 {
 }
 
+AssetCatalogTreeItemIterator AssetCatalogTreeItem::children()
+{
+  return AssetCatalogTreeItemIterator(children_.begin(), children_.end());
+}
+
 StringRef AssetCatalogTreeItem::get_name() const
 {
   return name_;
@@ -279,6 +286,56 @@ bool AssetCatalogTreeItem::has_children() const
   return !children_.empty();
 }
 
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeItemIterator::AssetCatalogTreeItemIterator(WrappedIterator wrapped_iterator,
+                                                           WrappedIterator wrapped_end_iterator)
+    : wrapped_iterator_(wrapped_iterator), wrapped_end_iterator_(wrapped_end_iterator)
+{
+}
+
+AssetCatalogTreeItemIterator AssetCatalogTreeItemIterator::begin() const
+{
+  return *this;
+}
+
+AssetCatalogTreeItemIterator AssetCatalogTreeItemIterator::end() const
+{
+  return AssetCatalogTreeItemIterator(wrapped_end_iterator_, wrapped_end_iterator_);
+}
+
+AssetCatalogTreeItem &AssetCatalogTreeItemIterator::operator*() const
+{
+  return wrapped_iterator_->second;
+}
+AssetCatalogTreeItem *AssetCatalogTreeItemIterator::operator->() const
+{
+  return &wrapped_iterator_->second;
+}
+
+AssetCatalogTreeItemIterator &AssetCatalogTreeItemIterator::operator++()
+{
+  ++wrapped_iterator_;
+  return *this;
+}
+AssetCatalogTreeItemIterator AssetCatalogTreeItemIterator::operator++(int)
+{
+  AssetCatalogTreeItemIterator copy(*this);
+  ++wrapped_iterator_;
+  return copy;
+}
+
+bool operator==(AssetCatalogTreeItemIterator a, AssetCatalogTreeItemIterator b)
+{
+  return a.wrapped_iterator_ == b.wrapped_iterator_;
+}
+bool operator!=(AssetCatalogTreeItemIterator a, AssetCatalogTreeItemIterator b)
+{
+  return a.wrapped_iterator_ != b.wrapped_iterator_;
+}
+
+/* ---------------------------------------------------------------------- */
+
 void AssetCatalogTree::insert_item(StringRef catalog_path_str)
 {
   /* #fs::path adds useful behavior to the path. Remember that on Windows it uses "\" as
@@ -304,6 +361,11 @@ void AssetCatalogTree::insert_item(StringRef catalog_path_str)
   }
 }
 
+AssetCatalogTreeItemIterator AssetCatalogTree::children()
+{
+  return AssetCatalogTreeItemIterator(children_.begin(), children_.end());
+}
+
 void AssetCatalogTree::foreach_item(const AssetCatalogTreeItem::ItemIterFn callback) const
 {
   AssetCatalogTreeItem::foreach_item_recursive(children_, callback);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7211cf9f893..683c39987de 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -84,6 +84,8 @@ typedef struct uiBlock uiBlock;
 typedef struct uiBut uiBut;
 typedef struct uiLayout uiLayout;
 typedef struct uiPopupBlockHandle uiPopupBlockHandle;
+/* C handle for C++ #uiAbstractTreeView type. */
+typedef struct uiAbstractTreeViewHandle uiAbstractTreeViewHandle;
 
 /* Defines */
 
@@ -389,6 +391,8 @@ typedef enum {
   UI_BTYPE_GRIP = 57 << 9,
   UI_BTYPE_DECORATOR = 58 << 9,
   UI_BTYPE_DATASETROW = 59 << 9,
+  /* An item in a tree view. Parent items may be collapsible. */
+  UI_BTYPE_TREEROW = 60 << 9,
 } eButType;
 
 #define BUTTYPE (63 << 9)
@@ -1672,6 +1676,7 @@ void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type
 void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain);
 uint8_t UI_but_datasetrow_component_get(uiBut *but);
 uint8_t UI_but_datasetrow_domain_get(uiBut *but);
+void UI_but_treerow_indentation_set(uiBut *but, int indentation);
 
 void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
 
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
new file mode 100644
index 00000000000..1aacc7081e0
--- /dev/null
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -0,0 +1,167 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup editorui
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "BLI_function_ref.hh"
+#include "BLI_vector.hh"
+
+#include "UI_resources.h"
+
+struct PointerRNA;
+struct uiBlock;
+struct uiBut;
+struct uiButTreeRow;
+struct uiLayout;
+
+namespace blender::ui {
+
+class uiAbstractTreeViewItem;
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Item Container
+ * \{ */
+
+/**
+ * Helper base class to expose common child-item data and functionality to both #uiAbstractTreeView
+ * and #uiAbstractTreeViewItem.
+ *
+ * That means this type can be used whenever either a #uiAbstractTreeView or a
+ * #uiAbstractTreeViewItem is needed.
+ */
+class uiTreeViewItemContainer {
+  friend class uiAbstractTreeView;
+  friend class uiAbstractTreeViewItem;
+
+  /* Private constructor, so only the friends above can create this! */
+  uiTreeViewItemContainer() = default;
+
+ protected:
+  Vector<std::unique_ptr<uiAbstractTreeViewItem>> children_;
+  /** Adding the first item to the root will set this, then it's passed on to all children. */
+  uiTreeViewItemContainer *root = nullptr;
+  /** Pointer back to the owning item. */
+  uiAbstractTreeViewItem *parent_ = nullptr;
+
+ public:
+  /**
+   * Convenience wrapper taking the arguments needed to construct an item of type \a ItemT. Calls
+   * the version just below.
+   */
+  template<class ItemT, typename... Args> ItemT &add_tree_item(Args &&...args)
+  {
+    static_assert(std::is_base_of<uiAbstractTreeViewItem, ItemT>::value,
+                  "Type must derive from and implement the uiAbstractTreeViewItem interface");
+
+    return dynamic_cast<ItemT &>(
+        add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+  }
+
+  uiAbstractTreeViewItem &add_tree_item(std::unique_ptr<uiAbstractTreeViewItem> item);
+};
+
+/** \} */
+
+/* ---------------------------------

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list