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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to