[Bf-blender-cvs] [925b82efb02] asset-browser-grid-view: Basic grid layout with big preview tiles

Julian Eisel noreply at git.blender.org
Fri Feb 4 15:21:45 CET 2022


Commit: 925b82efb02373f34ce577167c69be1b3dd72055
Author: Julian Eisel
Date:   Fri Feb 4 15:18:40 2022 +0100
Branches: asset-browser-grid-view
https://developer.blender.org/rB925b82efb02373f34ce577167c69be1b3dd72055

Basic grid layout with big preview tiles

Draws the asset previews in a grid layout, similar to the "old" Asset
Browser. No interactivity is supported yet.
The layout is managed through the grid-view.

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

M	source/blender/editors/include/UI_grid_view.hh
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/grid_view.cc
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_template_asset_view.cc
M	source/blender/editors/interface/interface_template_list.cc
M	source/blender/editors/space_assets/asset_browser_draw.cc
M	source/blender/editors/space_assets/asset_view.cc
M	source/blender/editors/space_assets/asset_view.hh
M	source/blender/editors/space_file/filesel.c

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

diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
index 945c9444db7..99aff838593 100644
--- a/source/blender/editors/include/UI_grid_view.hh
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -23,27 +23,145 @@
 
 #pragma once
 
+#include "BLI_function_ref.hh"
+#include "BLI_vector.hh"
+#include "UI_resources.h"
+
+struct PreviewImage;
+struct uiBlock;
+struct uiLayout;
 struct wmNotifier;
 
 namespace blender::ui {
 
+class AbstractGridView;
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Item Type
+ * \{ */
+
 class AbstractGridViewItem {
+  friend AbstractGridView;
+
+  const AbstractGridView *view_;
+
  public:
   virtual ~AbstractGridViewItem() = default;
 
+  virtual void build_grid_tile(uiLayout &layout) const = 0;
+
+  const AbstractGridView &get_view() const;
+
  protected:
   AbstractGridViewItem() = default;
 };
 
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Base Class
+ * \{ */
+
+struct GridViewStyle {
+  GridViewStyle(int width, int height);
+  int tile_width = 0;
+  int tile_height = 0;
+};
+
 class AbstractGridView {
+  friend class GridViewBuilder;
+  friend class GridViewLayoutBuilder;
+
+ protected:
+  Vector<std::unique_ptr<AbstractGridViewItem>> items_;
+  GridViewStyle style_;
+
  public:
+  AbstractGridView();
   virtual ~AbstractGridView() = default;
 
+  using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
+  void foreach_item(ItemIterFn iter_fn) const;
+
   /** Listen to a notifier, returning true if a redraw is needed. */
   virtual bool listen(const wmNotifier &) const;
 
-  // protected:
-  virtual void build() = 0;
+  /**
+   * Convenience wrapper constructing the item by forwarding given arguments to the constructor of
+   * the type (\a ItemT).
+   *
+   * E.g. if your grid-item type has the following constructor:
+   * \code{.cpp}
+   * MyGridItem(std::string str, int i);
+   * \endcode
+   * You can add an item like this:
+   * \code
+   * add_item<MyGridItem>("blabla", 42);
+   * \endcode
+   */
+  template<class ItemT, typename... Args> inline ItemT &add_item(Args &&...args);
+  const GridViewStyle &get_style() const;
+
+ protected:
+  virtual void build_items() = 0;
+
+ private:
+  /**
+   * Add an already constructed item, moving ownership to the grid-view.
+   * All items must be added through this, it handles important invariants!
+   */
+  AbstractGridViewItem &add_item(std::unique_ptr<AbstractGridViewItem> item);
 };
 
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Grid-View Builder
+ *
+ *  TODO unify this with `TreeViewBuilder` and call view-specific functions via type erased view?
+ * \{ */
+
+class GridViewBuilder {
+  uiBlock &block_;
+
+ public:
+  GridViewBuilder(uiBlock &block);
+
+  void build_grid_view(AbstractGridView &grid_view);
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Predefined Grid-View Item Types
+ *
+ *  Common, Basic Grid-View Item Types.
+ * \{ */
+
+/**
+ * A grid item that shows preview image icons at a nicely readable size (multiple of the normal UI
+ * unit size).
+ */
+class PreviewGridItem : public AbstractGridViewItem {
+ public:
+  std::string label{};
+  int preview_icon_id = ICON_NONE;
+
+  PreviewGridItem(StringRef label, int preview_icon_id);
+
+  void build_grid_tile(uiLayout &layout) const override;
+};
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+
+template<class ItemT, typename... Args> inline ItemT &AbstractGridView::add_item(Args &&...args)
+{
+  static_assert(std::is_base_of<AbstractGridViewItem, ItemT>::value,
+                "Type must derive from and implement the AbstractGridViewItem interface");
+
+  return dynamic_cast<ItemT &>(add_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
+}
+
 }  // namespace blender::ui
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index cdc7eb25b4c..e5ef3bb2806 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1788,6 +1788,14 @@ AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen);
 void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name);
 int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
 
+/**
+ * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable
+ * preview with label in.
+ */
+int UI_preview_tile_size_x(void);
+int UI_preview_tile_size_y(void);
+int UI_preview_tile_size_y_no_label(void);
+
 /* Panels
  *
  * Functions for creating, freeing and drawing panels. The API here
diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/grid_view.cc
index 5315bd1447e..72614319bf9 100644
--- a/source/blender/editors/interface/grid_view.cc
+++ b/source/blender/editors/interface/grid_view.cc
@@ -18,9 +18,12 @@
  * \ingroup edinterface
  */
 
+#include <stdexcept>
+
 #include "WM_types.h"
 
 #include "UI_interface.h"
+#include "interface_intern.h"
 
 #include "UI_grid_view.hh"
 
@@ -28,12 +31,137 @@ namespace blender::ui {
 
 /* ---------------------------------------------------------------------- */
 
+AbstractGridView::AbstractGridView() : style_(UI_preview_tile_size_x(), UI_preview_tile_size_y())
+{
+}
+
+AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridViewItem> item)
+{
+  items_.append(std::move(item));
+
+  AbstractGridViewItem &added_item = *items_.last();
+  added_item.view_ = this;
+  return added_item;
+}
+
+void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
+{
+  for (auto &item_ptr : items_) {
+    iter_fn(*item_ptr);
+  }
+}
+
 bool AbstractGridView::listen(const wmNotifier &) const
 {
   /* Nothing by default. */
   return false;
 }
 
+const GridViewStyle &AbstractGridView::get_style() const
+{
+  return style_;
+}
+
+GridViewStyle::GridViewStyle(int width, int height) : tile_width(width), tile_height(height)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+
+const AbstractGridView &AbstractGridViewItem::get_view() const
+{
+  if (UNLIKELY(!view_)) {
+    throw std::runtime_error(
+        "Invalid state, item must be added through AbstractGridView::add_item()");
+  }
+  return *view_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+class GridViewLayoutBuilder {
+  uiBlock &block_;
+
+  friend GridViewBuilder;
+
+ public:
+  GridViewLayoutBuilder(uiBlock &block);
+
+  void build_from_view(const AbstractGridView &grid_view);
+  uiLayout *current_layout() const;
+};
+
+GridViewLayoutBuilder::GridViewLayoutBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewLayoutBuilder::build_from_view(const AbstractGridView &grid_view)
+{
+  uiLayout &layout = *uiLayoutColumn(current_layout(), false);
+  const GridViewStyle &style = grid_view.get_style();
+
+  const int cols_per_row = uiLayoutGetWidth(&layout) / style.tile_width;
+  uiLayout *grid_layout = uiLayoutGridFlow(&layout, true, cols_per_row, true, true, true);
+
+  grid_view.foreach_item([&](AbstractGridViewItem &item) { item.build_grid_tile(*grid_layout); });
+}
+
+uiLayout *GridViewLayoutBuilder::current_layout() const
+{
+  return block_.curlayout;
+}
+
+/* ---------------------------------------------------------------------- */
+
+GridViewBuilder::GridViewBuilder(uiBlock &block) : block_(block)
+{
+}
+
+void GridViewBuilder::build_grid_view(AbstractGridView &grid_view)
+{
+  grid_view.build_items();
+
+  GridViewLayoutBuilder builder(block_);
+  builder.build_from_view(grid_view);
+  //  grid_view.update_from_old(block_);
+  //  grid_view.change_state_delayed();
+
+  //  TreeViewLayoutBuilder builder(block_);
+  //  builder.build_from_tree(tree_view);
+}
+
+/* ---------------------------------------------------------------------- */
+
+PreviewGridItem::PreviewGridItem(StringRef label, int preview_icon_id)
+    : label(label), preview_icon_id(preview_icon_id)
+{
+}
+
+void PreviewGridItem::build_grid_tile(uiLayout &layout) const
+{
+  const GridViewStyle &style = get_view().get_style();
+  uiBlock *block = uiLayoutGetBlock(&layout);
+  uiBut *but = uiDefIconTextBut(block,
+                                UI_BTYPE_PREVIEW_TILE,
+                                0,
+                                preview_icon_id,
+                                label.c_str(),
+                                0,
+                                0,
+                                style.tile_width,
+                                style.tile_height,
+                                nullptr,
+                                0,
+                                0,
+                                0,
+                                0,
+                                "");
+  ui_def_but_icon(but,
+                  preview_icon_id,
+                  /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
+                  UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+}
+
 }  // namespace blender::ui
 
 using namespace blender::ui;
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 2292bf759b7..3cbea922bed 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4910,6 +4910,21 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
   return match;
 }
 
+int UI_preview_tile_size_x(void)
+{
+  return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_X);
+}
+
+int UI_preview_tile_size_y(void)
+{
+  return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y);
+}
+
+int UI_preview_tile_size_y_no_label(void)
+{
+  return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y - UI_UNIT_Y);
+}
+
 static void ui_but_update_and_icon_set(uiBut *but, int icon)
 {
   if (icon) {
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 0a3cff5fa98..2a26ff96105 100644
--- a/source/blender/e

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list