[Bf-blender-cvs] [1832e11f39a] master: UI: Support dragging tree-view items

Julian Eisel noreply at git.blender.org
Wed Oct 27 14:57:47 CEST 2021


Commit: 1832e11f39a36681533c148de9300b290a8c309c
Author: Julian Eisel
Date:   Wed Oct 27 14:48:00 2021 +0200
Branches: master
https://developer.blender.org/rB1832e11f39a36681533c148de9300b290a8c309c

UI: Support dragging tree-view items

Adds the needed bits to the UI tree-view API to support dragging
tree-view items. This isn't used yet, but will be in the following
commit for asset catalogs.

There will probably be some further tweaks to the design at some point,
for now this should work well enough for our use-cases.

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

M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/include/UI_tree_view.hh
M	source/blender/editors/interface/interface_handlers.c
M	source/blender/editors/interface/tree_view.cc

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

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 12fdda2092c..0f290d4255b 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2777,6 +2777,7 @@ void UI_interface_tag_script_reload(void);
 
 bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
 bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
+bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
 bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
                                 const struct wmDrag *drag,
                                 const char **r_disabled_hint);
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 905181a7251..0990d844d48 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -49,6 +49,7 @@ namespace blender::ui {
 class AbstractTreeView;
 class AbstractTreeViewItem;
 class AbstractTreeViewItemDropController;
+class AbstractTreeViewItemDragController;
 
 /* ---------------------------------------------------------------------- */
 /** \name Tree-View Item Container
@@ -273,6 +274,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
    */
   virtual bool matches(const AbstractTreeViewItem &other) const;
 
+  /**
+   * If an item wants to support being dragged, it has to return a drag controller here.
+   * That is an object implementing #AbstractTreeViewItemDragController.
+   */
+  virtual std::unique_ptr<AbstractTreeViewItemDragController> 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 #AbstractTreeViewItemDropController.
@@ -347,6 +353,18 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
 /** \name Drag 'n Drop
  * \{ */
 
+/**
+ * Class to enable dragging a tree-item. An item can return a drop controller for itself via a
+ * custom implementation of #AbstractTreeViewItem::create_drag_controller().
+ */
+class AbstractTreeViewItemDragController {
+ public:
+  virtual ~AbstractTreeViewItemDragController() = default;
+
+  virtual int get_drag_type() const = 0;
+  virtual void *create_drag_data() const = 0;
+};
+
 /**
  * Class to customize the drop behavior of a tree-item, plus the behavior when dragging over this
  * item. An item can return a drop controller for itself via a custom implementation of
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index b21d2127030..6dd6f9eb359 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2145,6 +2145,12 @@ static bool ui_but_drag_init(bContext *C,
         return false;
       }
     }
+    else if (but->type == UI_BTYPE_TREEROW) {
+      uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+      if (tree_row_but->tree_item) {
+        UI_tree_view_item_drag_start(C, tree_row_but->tree_item);
+      }
+    }
     else {
       wmDrag *drag = WM_event_start_drag(
           C,
@@ -4821,19 +4827,33 @@ static int ui_do_but_TREEROW(bContext *C,
 
   if (data->state == BUTTON_STATE_HIGHLIGHT) {
     if (event->type == LEFTMOUSE) {
-      if (event->val == KM_CLICK) {
-        button_activate_state(C, but, BUTTON_STATE_EXIT);
-        return WM_UI_HANDLER_BREAK;
-      }
-      if (event->val == KM_DBL_CLICK) {
-        data->cancel = true;
+      switch (event->val) {
+        case KM_PRESS:
+          /* Extra icons have priority, don't mess with them. */
+          if (ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
+            return WM_UI_HANDLER_BREAK;
+          }
+          button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+          data->dragstartx = event->xy[0];
+          data->dragstarty = event->xy[1];
+          return WM_UI_HANDLER_CONTINUE;
 
-        UI_tree_view_item_begin_rename(tree_row_but->tree_item);
-        ED_region_tag_redraw(CTX_wm_region(C));
-        return WM_UI_HANDLER_BREAK;
+        case KM_CLICK:
+          button_activate_state(C, but, BUTTON_STATE_EXIT);
+          return WM_UI_HANDLER_BREAK;
+
+        case KM_DBL_CLICK:
+          data->cancel = true;
+          UI_tree_view_item_begin_rename(tree_row_but->tree_item);
+          ED_region_tag_redraw(CTX_wm_region(C));
+          return WM_UI_HANDLER_BREAK;
       }
     }
   }
+  else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+    /* Let "default" button handling take care of the drag logic. */
+    return ui_do_but_EXIT(C, but, data, event);
+  }
 
   return WM_UI_HANDLER_CONTINUE;
 }
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index 04d7a066b36..c08fa51d5a5 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -29,6 +29,7 @@
 
 #include "UI_interface.h"
 
+#include "WM_api.h"
 #include "WM_types.h"
 
 #include "UI_tree_view.hh"
@@ -354,6 +355,13 @@ void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
   is_active_fn_ = is_active_fn;
 }
 
+std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
+    const
+{
+  /* There's no drag controller (and hence no drag support) by default. */
+  return nullptr;
+}
+
 std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
     const
 {
@@ -686,6 +694,29 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
   return a.matches_including_parents(b);
 }
 
+/**
+ * Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
+ * support dragging, i.e. it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
+ */
+bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
+{
+  const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+  const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
+      item.create_drag_controller();
+  if (!drag_controller) {
+    return false;
+  }
+
+  WM_event_start_drag(C,
+                      ICON_NONE,
+                      drag_controller->get_drag_type(),
+                      drag_controller->create_drag_data(),
+                      0,
+                      WM_DRAG_FREE_DATA);
+  return true;
+}
+
 bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
                                 const wmDrag *drag,
                                 const char **r_disabled_hint)



More information about the Bf-blender-cvs mailing list