[Bf-blender-cvs] [323fd80aada] master: UI: Tree-View API for easy creation of tree UIs

Julian Eisel noreply at git.blender.org
Thu Sep 23 19:35:04 CEST 2021


Commit: 323fd80aada46105e23985f5646f9252b5e6f193
Author: Julian Eisel
Date:   Thu Sep 23 18:56:29 2021 +0200
Branches: master
https://developer.blender.org/rB323fd80aada46105e23985f5646f9252b5e6f193

UI: Tree-View API for easy creation of tree UIs

This follows three main targets:

* Make creation of new tree UIs easy.
* Groundwork to generalize tree UIs (so e.g. Outliner, animation
  channels, asset catalogs and spreadsheet data-sets don't have to
  re-implement basic tree UI code) or even other data-view UIs.
* Better separate data and UI state. E.g. with this, tree-item selection
  or the open/collapsed state can be stored on the UI level, rather than
  in data. (Asset Catalogs need this, storing UI state info in them is
  not an option.)

In addition, the design should be well testable and could even be
exposed to Python.

Note that things will likely change in master still. E.g. the actually
resulting UI isn't very nice visually yet.

The design is documented here:
https://wiki.blender.org/wiki/Source/Interface/Views

Differential Revision: https://developer.blender.org/D12573

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

M	source/blender/editors/include/UI_interface.h
A	source/blender/editors/include/UI_interface.hh
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
A	source/blender/editors/interface/interface_view.cc
M	source/blender/editors/interface/interface_widgets.c
A	source/blender/editors/interface/tree_view.cc
M	source/blender/editors/util/CMakeLists.txt

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

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 916105b0f8e..f7842270746 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -84,6 +84,10 @@ typedef struct uiBlock uiBlock;
 typedef struct uiBut uiBut;
 typedef struct uiLayout uiLayout;
 typedef struct uiPopupBlockHandle uiPopupBlockHandle;
+/* C handle for C++ #ui::AbstractTreeView type. */
+typedef struct uiTreeViewHandle uiTreeViewHandle;
+/* C handle for C++ #ui::AbstractTreeViewItem type. */
+typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
 
 /* Defines */
 
@@ -389,6 +393,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 +1678,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]);
 
@@ -2754,6 +2761,8 @@ void UI_interface_tag_script_reload(void);
 /* Support click-drag motion which presses the button and closes a popover (like a menu). */
 #define USE_UI_POPOVER_ONCE
 
+bool UI_tree_view_item_is_active(uiTreeViewItemHandle *item_);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
new file mode 100644
index 00000000000..4a583d0225e
--- /dev/null
+++ b/source/blender/editors/include/UI_interface.hh
@@ -0,0 +1,35 @@
+/*
+ * 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 "BLI_string_ref.hh"
+
+struct uiBlock;
+namespace blender::ui {
+class AbstractTreeView;
+}
+
+blender::ui::AbstractTreeView *UI_block_add_view(
+    uiBlock &block,
+    blender::StringRef idname,
+    std::unique_ptr<blender::ui::AbstractTreeView> tree_view);
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..51b8e65521a
--- /dev/null
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -0,0 +1,238 @@
+/*
+ * 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 AbstractTreeView;
+class AbstractTreeViewItem;
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Item Container
+ * \{ */
+
+/**
+ * Helper base class to expose common child-item data and functionality to both #AbstractTreeView
+ * and #AbstractTreeViewItem.
+ *
+ * That means this type can be used whenever either a #AbstractTreeView or a
+ * #AbstractTreeViewItem is needed.
+ */
+class TreeViewItemContainer {
+  friend class AbstractTreeView;
+  friend class AbstractTreeViewItem;
+
+  /* Private constructor, so only the friends above can create this! */
+  TreeViewItemContainer() = default;
+
+ protected:
+  Vector<std::unique_ptr<AbstractTreeViewItem>> children_;
+  /** Adding the first item to the root will set this, then it's passed on to all children. */
+  TreeViewItemContainer *root_ = nullptr;
+  /** Pointer back to the owning item. */
+  AbstractTreeViewItem *parent_ = nullptr;
+
+ public:
+  enum class IterOptions {
+    None = 0,
+    SkipCollapsed = 1 << 0,
+
+    /* Keep ENUM_OPERATORS() below updated! */
+  };
+  using ItemIterFn = FunctionRef<void(AbstractTreeViewItem &)>;
+
+  /**
+   * 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<AbstractTreeViewItem, ItemT>::value,
+                  "Type must derive from and implement the AbstractTreeViewItem interface");
+
+    return dynamic_cast<ItemT &>(
+        add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+  }
+
+  AbstractTreeViewItem &add_tree_item(std::unique_ptr<AbstractTreeViewItem> item);
+
+ protected:
+  void foreach_item_recursive(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
+};
+
+ENUM_OPERATORS(TreeViewItemContainer::IterOptions,
+               TreeViewItemContainer::IterOptions::SkipCollapsed);
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Builders
+ * \{ */
+
+class TreeViewBuilder {
+  uiBlock &block_;
+
+ public:
+  TreeViewBuilder(uiBlock &block);
+
+  void build_tree_view(AbstractTreeView &tree_view);
+};
+
+class TreeViewLayoutBuilder {
+  uiBlock &block_;
+
+  friend TreeViewBuilder;
+
+ public:
+  void build_row(AbstractTreeViewItem &item) const;
+  uiBlock &block() const;
+  uiLayout *current_layout() const;
+
+ private:
+  /* Created through #TreeViewBuilder. */
+  TreeViewLayoutBuilder(uiBlock &block);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Base Class
+ * \{ */
+
+class AbstractTreeView : public TreeViewItemContainer {
+  friend TreeViewBuilder;
+  friend TreeViewLayoutBuilder;
+
+ public:
+  virtual ~AbstractTreeView() = default;
+
+  void foreach_item(ItemIterFn iter_fn, IterOptions options = IterOptions::None) const;
+
+ protected:
+  virtual void build_tree() = 0;
+
+ private:
+  /** Match the tree-view against an earlier version of itself (if any) and copy the old UI state
+   * (e.g. collapsed, active, selected) to the new one. See
+   * #AbstractTreeViewItem.update_from_old(). */
+  void update_from_old(uiBlock &new_block);
+  static void update_children_from_old_recursive(const TreeViewItemContainer &new_items,
+                                                 const TreeViewItemContainer &old_items);
+  static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
+                                                   const TreeViewItemContainer &items);
+  void build_layout_from_tree(const TreeViewLayoutBuilder &builder);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Tree-View Item Type
+ * \{ */
+
+/** \brief Abstract base class for defining a customizable tree-view item.
+ *
+ * The tree-view item defines how to build its data into a tree-row. There are implementations for
+ * common layouts, e.g. #BasicTreeViewItem.
+ * It also stores state information that needs to be persistent over redraws, like the collapsed
+ * state.
+ */
+class AbstractTreeViewItem : public TreeViewItemContainer {
+  friend class AbstractTreeView;
+
+  bool is_open_ = false;
+  bool is_active_ = false;
+
+ protected:
+  /** This label is used for identifying an item (together with its parent's labels). */
+  std::string label_{};
+
+ public:
+  virtual ~AbstractTreeViewItem() = default;
+
+  virtual void build_row(uiLayout &row) = 0;
+
+  virtual void on_activate();
+
+  /** Copy persistent state (e.g. is-collapsed flag, selection, etc.) from a matching item of the
+   * last redraw to this item. If sub-classes introduce more advanced state they should override
+   * this and make it update their state accordingly. */
+  virtual void update_from_old(AbstractTreeViewItem &old);
+
+  const AbstractTreeView &get_tree_view() const;
+  int count_parents() const;
+  void set_active(bool value = true);
+  bool is_active() const;
+  void toggle_collapsed();
+  bool is_collapsed() const;
+  void set_collapsed(bool collapsed);
+  bool is_collapsible() const;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Predefined Tree-View Item Types
+ *
+ *  Common, Basic Tree-View Item Types.
+ * \{ */
+
+/**
+ * The most basic type, just a label with an icon.
+ */
+class BasicTreeViewItem : public AbstractTreeViewItem {
+ public:
+  using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
+  BIFIconID icon;
+
+  BasicTreeViewItem(StringRef label, BIFIconID icon = ICON_NONE, ActivateFn activate_fn = nullptr);
+
+  void build_row(uiLayout &row) override;
+  void on_activate() override;
+
+ protected:
+  /** Created in the #build() function. */
+  uiButTreeRow *tree_row_but_ = nullptr;
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list