[Bf-blender-cvs] [5bee991132e] master: UI: Port view item features to base class, merge view item button types

Julian Eisel noreply at git.blender.org
Tue Jul 19 16:32:34 CEST 2022


Commit: 5bee991132ea8aa7fea827df5b5153f3211a3431
Author: Julian Eisel
Date:   Tue Jul 19 16:14:42 2022 +0200
Branches: master
https://developer.blender.org/rB5bee991132ea8aa7fea827df5b5153f3211a3431

UI: Port view item features to base class, merge view item button types

No user visible changes expected.

Merges the tree row and grid tile button types, which were mostly doing
the same things. The idea is that there is a button type for
highlighting, as well as supporting general view item features (e.g.
renaming, drag/drop, etc.). So instead there is a view item button type
now. Also ports view item features like renaming, custom context menus,
drag controllers and drop controllers to `ui::AbstractViewItem` (the new
base class for all view items).

This should be quite an improvement because:
- Merges code that was duplicated over view items.
- Mentioned features (renaming, drag & drop, ...) are much easier to
  implement in new view types now. Most of it comes "for free".
- Further features will immediately become availalbe to all views (e.g.
  selection).
- Simplifies APIs, there don't have to be functions for individual view
  item types anymore.
- View item classes are split and thus less overwhelming visually.
- View item buttons now share all code (drawing, handling, etc.)
- We're soon running out of available button types, this commit merges
  two into one.

I was hoping I could do this in multiple smaller commits, but things
were quite intertwined so that would've taken quite some effort.

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

M	source/blender/editors/include/UI_abstract_view.hh
M	source/blender/editors/include/UI_grid_view.hh
M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/include/UI_tree_view.hh
M	source/blender/editors/interface/abstract_view.cc
M	source/blender/editors/interface/abstract_view_item.cc
M	source/blender/editors/interface/grid_view.cc
M	source/blender/editors/interface/interface.cc
M	source/blender/editors/interface/interface_context_menu.c
M	source/blender/editors/interface/interface_dropboxes.cc
M	source/blender/editors/interface/interface_handlers.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_ops.c
M	source/blender/editors/interface/interface_query.cc
M	source/blender/editors/interface/interface_view.cc
M	source/blender/editors/interface/interface_widgets.c
M	source/blender/editors/interface/tree_view.cc
M	source/blender/editors/space_file/asset_catalog_tree_view.cc
M	source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc

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

diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh
index fdb7069e7c4..dfddace8899 100644
--- a/source/blender/editors/include/UI_abstract_view.hh
+++ b/source/blender/editors/include/UI_abstract_view.hh
@@ -3,11 +3,16 @@
 /** \file
  * \ingroup editorui
  *
- * Base for all views (UIs to display data sets), supporting common features.
+ * Base class for all views (UIs to display data sets) and view items, supporting common features.
  * https://wiki.blender.org/wiki/Source/Interface/Views
  *
  * One of the most important responsibilities of the base class is managing reconstruction,
- * enabling state that is persistent over reconstructions/redraws.
+ * enabling state that is persistent over reconstructions/redraws. Other features:
+ * - Renaming
+ * - Custom context menus
+ * - Notifier listening
+ * - Drag controllers (dragging view items)
+ * - Drop controllers (dropping onto/into view items)
  */
 
 #pragma once
@@ -18,15 +23,25 @@
 #include "DNA_defs.h"
 
 #include "BLI_span.hh"
+#include "BLI_string_ref.hh"
 
-struct wmNotifier;
+struct bContext;
 struct uiBlock;
+struct uiBut;
+struct uiLayout;
+struct uiViewItemHandle;
+struct wmDrag;
+struct wmNotifier;
 
 namespace blender::ui {
 
 class AbstractViewItem;
+class AbstractViewItemDropController;
+class AbstractViewItemDragController;
 
 class AbstractView {
+  friend class AbstractViewItem;
+
   bool is_reconstructed_ = false;
   /**
    * Only one item can be renamed at a time. So rather than giving each item an own rename buffer
@@ -43,6 +58,12 @@ class AbstractView {
   /** Listen to a notifier, returning true if a redraw is needed. */
   virtual bool listen(const wmNotifier &) const;
 
+  /**
+   * Makes \a item valid for display in this view. Behavior is undefined for items not registered
+   * with this.
+   */
+  void register_item(AbstractViewItem &item);
+
   /** Only one item can be renamed at a time. */
   bool is_renaming() const;
   /** \return If renaming was started successfully. */
@@ -63,7 +84,6 @@ class AbstractView {
    * After this, reconstruction is complete (see #is_reconstructed()).
    */
   void update_from_old(uiBlock &new_block);
-
   /**
    * Check if the view is fully (re-)constructed. That means, both the build function and
    * #update_from_old() have finished.
@@ -72,15 +92,85 @@ class AbstractView {
 };
 
 class AbstractViewItem {
+  friend class AbstractView;
+  friend class ViewItemAPIWrapper;
+
  protected:
+  /**
+   * The view this item is a part of, and was registered for using #AbstractView::register_item().
+   * If this wasn't done, the behavior of items is undefined.
+   */
+  AbstractView *view_ = nullptr;
   bool is_active_ = false;
+  bool is_renaming_ = false;
 
  public:
   virtual ~AbstractViewItem() = default;
 
+  virtual void build_context_menu(bContext &C, uiLayout &column) const;
+
+  /**
+   * Queries if the view item supports renaming in principle. Renaming may still fail, e.g. if
+   * another item is already being renamed.
+   */
+  virtual bool supports_renaming() const;
+  /**
+   * Try renaming the item, or the data it represents. Can assume
+   * #AbstractViewItem::supports_renaming() returned true. Sub-classes that override this should
+   * usually call this, unless they have a custom #AbstractViewItem.matches() implementation.
+   *
+   * \return True if the renaming was successful.
+   */
+  virtual bool rename(StringRefNull new_name);
+  /**
+   * Get the string that should be used for renaming, typically the item's label. This string will
+   * not be modified, but if the renaming is canceled, the value will be reset to this.
+   */
+  virtual StringRef get_rename_string() const;
+
+  /**
+   * If an item wants to support being dragged, it has to return a drag controller here.
+   * That is an object implementing #AbstractViewItemDragController.
+   */
+  virtual std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const;
+  /**
+   * If an item wants to support dropping data into it, it has to return a drop controller here.
+   * That is an object implementing #AbstractViewItemDropController.
+   *
+   * \note This drop controller may be requested for each event. The view doesn't keep a drop
+   *       controller around currently. So it can not contain persistent state.
+   */
+  virtual std::unique_ptr<AbstractViewItemDropController> create_drop_controller() const;
+
+  /** Get the view this item is registered for using #AbstractView::register_item(). */
+  AbstractView &get_view() const;
+
+  /**
+   * Requires the view to have completed reconstruction, see #is_reconstructed(). Otherwise we
+   * can't be sure about the item state.
+   */
+  bool is_active() const;
+
+  bool is_renaming() const;
+  void begin_renaming();
+  void end_renaming();
+  void rename_apply();
+
+  template<typename ToType = AbstractViewItem>
+  static ToType *from_item_handle(uiViewItemHandle *handle);
+
  protected:
   AbstractViewItem() = default;
 
+  /**
+   * Compare this item's identity to \a other to check if they represent the same data.
+   * Implementations can assume that the types match already (caller must check).
+   *
+   * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
+   * renaming, etc.).
+   */
+  virtual bool matches(const AbstractViewItem &other) const = 0;
+
   /**
    * Copy persistent state (e.g. active, selection, etc.) from a matching item of
    * the last redraw to this item. If sub-classes introduce more advanced state they should
@@ -90,7 +180,101 @@ class AbstractViewItem {
    */
   virtual void update_from_old(const AbstractViewItem &old);
 
-  void set_view(AbstractView &view);
+  /**
+   * Add a text button for renaming the item to \a block. This must be used for the built-in
+   * renaming to work. This button is meant to appear temporarily. It is removed when renaming is
+   * done.
+   */
+  void add_rename_button(uiBlock &block);
 };
 
+template<typename ToType> ToType *AbstractViewItem::from_item_handle(uiViewItemHandle *handle)
+{
+  static_assert(std::is_base_of<AbstractViewItem, ToType>::value,
+                "Type must derive from and implement the AbstractViewItem interface");
+
+  return dynamic_cast<ToType *>(reinterpret_cast<AbstractViewItem *>(handle));
+}
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+/**
+ * Class to enable dragging a view item. An item can return a drop controller for itself by
+ * implementing #AbstractViewItem::create_drag_controller().
+ */
+class AbstractViewItemDragController {
+ protected:
+  AbstractView &view_;
+
+ public:
+  AbstractViewItemDragController(AbstractView &view);
+  virtual ~AbstractViewItemDragController() = default;
+
+  virtual int get_drag_type() const = 0;
+  virtual void *create_drag_data() const = 0;
+  virtual void on_drag_start();
+
+  /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+   * exception if the view is not of the requested type. */
+  template<class ViewType> inline ViewType &get_view() const;
+};
+
+/**
+ * Class to define the behavior when dropping something onto/into a view item, plus the behavior
+ * when dragging over this item. An item can return a drop controller for itself via a custom
+ * implementation of #AbstractViewItem::create_drop_controller().
+ */
+class AbstractViewItemDropController {
+ protected:
+  AbstractView &view_;
+
+ public:
+  AbstractViewItemDropController(AbstractView &view);
+  virtual ~AbstractViewItemDropController() = default;
+
+  /**
+   * Check if the data dragged with \a drag can be dropped on the item this controller is for.
+   * \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
+   *                         isn't possible on this item. Shouldn't be done too aggressively, e.g.
+   *                         don't set this if the drag-type can't be dropped here; only if it can
+   *                         but there's another reason it can't be dropped.
+   *                         Can assume this is a non-null pointer.
+   */
+  virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
+  /**
+   * Custom text to display when dragging over a view item. Should explain what happens when
+   * dropping the data onto this item. Will only be used if #AbstractViewItem::can_drop()
+   * returns true, so the implementing override doesn't have to check that again.
+   * The returned value must be a translated string.
+   */
+  virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
+  /**
+   * Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
+   * controller is for.
+   */
+  virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
+
+  /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+   * exception if the view is not of the requested type. */
+  template<class ViewType> inline ViewType &get_view() const;
+};
+
+template<class ViewType> ViewType &AbstractViewItemDragController::get_view() const
+{
+  static_assert(std::is_base_of<AbstractView, ViewType>::value,
+                "Type must derive from and implement the ui::AbstractView interface");
+  return dynamic_cast<ViewType &>(view_);
+}
+
+template<class ViewType> ViewType &AbstractViewItemDropController::get_view() const
+{
+  static_assert(std::is_base_of<AbstractView, ViewType>::value,
+                "Type must derive from and implement the ui::AbstractView interface");
+  return dynamic_cast<ViewType &>(view_);
+}
+
+/** \} */
+
 }  // namespace blender::ui
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
index 74ce16ccd85..805198f38ef 100644
--- a/source/blender/editors/include/UI_grid_view.hh
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -19,7 +19,7 @@
 struct bContext;
 struct PreviewImage;
 struct uiBlock;
-struct uiButGridTile;
+struct uiButViewItem;
 struct uiLayout;
 struct View2D;
 struct wmNotifier;
@@ -41,32 +41,22 @@ class AbstractGridViewIt

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list