Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2021-09-30 17:26:56 +0300
committerJulian Eisel <julian@blender.org>2021-09-30 17:39:09 +0300
commit4ee2d9df428d16f07e351f5554b951ae75804ea0 (patch)
treea10641e618b9de7aeec38248ebf3a1dfad257abc /source/blender/editors
parent42ce88f15cb77c859c6b2fed119934836235b961 (diff)
UI: Support easy dropping into/onto rows in new tree-view API
Adds an easy way to add drop support for tree-view rows. Most of the work is handled by the tree-view UI code. The tree items can simply override a few functions (`can_drop()`, `on_drop()`, `drop_tooltip()`) to implement their custom drop behavior. While dragging over a tree-view item that can be dropped into/onto, the item can show a custom and dynamic tooltip explaining what's gonna happen on drop. This isn't used yet, but will soon be for asset catalogs. See documentation here: https://wiki.blender.org/wiki/Source/Interface/Views#Further_Customizations
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/UI_interface.h9
-rw-r--r--source/blender/editors/include/UI_tree_view.hh20
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc66
-rw-r--r--source/blender/editors/interface/interface_intern.h1
-rw-r--r--source/blender/editors/interface/interface_ops.c47
-rw-r--r--source/blender/editors/interface/interface_query.c10
-rw-r--r--source/blender/editors/interface/interface_view.cc17
-rw-r--r--source/blender/editors/interface/tree_view.cc52
-rw-r--r--source/blender/editors/screen/area.c3
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
11 files changed, 223 insertions, 4 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 106f6166760..f642895f64e 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2593,6 +2593,7 @@ typedef struct uiDragColorHandle {
void ED_operatortypes_ui(void);
void ED_keymap_ui(struct wmKeyConfig *keyconf);
+void ED_dropboxes_ui(void);
void ED_uilisttypes_ui(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
@@ -2763,6 +2764,14 @@ 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_can_drop(const uiTreeViewItemHandle *item_, const struct wmDrag *drag);
+bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const struct ListBase *drags);
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item,
+ const struct bContext *C,
+ const struct wmDrag *drag,
+ const struct wmEvent *event);
+
+uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region, int x, int y);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 81a614cd195..d36e688dd65 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -29,11 +29,14 @@
#include "UI_resources.h"
+struct bContext;
struct PointerRNA;
struct uiBlock;
struct uiBut;
struct uiButTreeRow;
struct uiLayout;
+struct wmEvent;
+struct wmDrag;
namespace blender::ui {
@@ -185,10 +188,19 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
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 bool on_drop(const wmDrag &drag);
+ virtual bool can_drop(const wmDrag &drag) const;
+ /** Custom text to display when dragging over a tree item. Should explain what happens when
+ * dropping the data onto this item. Will only be used if #AbstractTreeViewItem::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 bContext &C,
+ const wmDrag &drag,
+ const wmEvent &event) const;
+
+ /** 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(const AbstractTreeViewItem &old);
/** Compare this item to \a other to check if they represent the same data. This is critical for
* being able to recognize an item from a previous redraw, to be able to keep its state (e.g.
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 79e08f46292..8fcc704a301 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
interface_button_group.c
interface_context_menu.c
interface_draw.c
+ interface_dropboxes.cc
interface_eyedropper.c
interface_eyedropper_color.c
interface_eyedropper_colorband.c
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
new file mode 100644
index 00000000000..cb33e7f736e
--- /dev/null
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 edinterface
+ */
+
+#include "BKE_context.h"
+
+#include "DNA_space_types.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+
+static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
+ region, event->x, event->y);
+ if (!hovered_tree_item) {
+ return false;
+ }
+
+ return UI_tree_view_item_can_drop(hovered_tree_item, drag);
+}
+
+static char *ui_tree_view_drop_tooltip(bContext *C,
+ wmDrag *drag,
+ const wmEvent *event,
+ wmDropBox *UNUSED(drop))
+{
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
+ region, event->x, event->y);
+ if (!hovered_tree_item) {
+ return nullptr;
+ }
+
+ return UI_tree_view_item_drop_tooltip(hovered_tree_item, C, drag, event);
+}
+
+void ED_dropboxes_ui()
+{
+ ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
+
+ WM_dropbox_add(lb,
+ "UI_OT_tree_view_drop",
+ ui_tree_view_drop_poll,
+ nullptr,
+ nullptr,
+ ui_tree_view_drop_tooltip);
+}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 95e6791b359..8b45d9faae6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1171,6 +1171,7 @@ uiBut *ui_list_row_find_mouse_over(const struct ARegion *region,
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
const int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
+uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int x, const int y);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 7b59a6f7263..1fc07bce341 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1918,6 +1918,51 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name UI Tree-View Drop Operator
+ * \{ */
+
+static bool ui_tree_view_drop_poll(bContext *C)
+{
+ const wmWindow *win = CTX_wm_window(C);
+ const ARegion *region = CTX_wm_region(C);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
+ region, win->eventstate->x, win->eventstate->y);
+
+ return hovered_tree_item != NULL;
+}
+
+static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ if (event->custom != EVT_DATA_DRAGDROP) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
+ const ARegion *region = CTX_wm_region(C);
+ uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
+ region, event->x, event->y);
+
+ if (!UI_tree_view_item_drop_handle(hovered_tree_item, event->customdata)) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_tree_view_drop(wmOperatorType *ot)
+{
+ ot->name = "Tree View drop";
+ ot->idname = "UI_OT_tree_view_drop";
+ ot->description = "Drag and drop items onto a tree item";
+
+ ot->invoke = ui_tree_view_drop_invoke;
+ ot->poll = ui_tree_view_drop_poll;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Operator & Keymap Registration
* \{ */
@@ -1944,6 +1989,8 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_list_start_filter);
+ WM_operatortype_append(UI_OT_tree_view_drop);
+
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
WM_operatortype_append(UI_OT_eyedropper_colorramp);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 15d1d2f2eec..2f6bda3252d 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -463,6 +463,16 @@ uiBut *ui_list_row_find_from_index(const ARegion *region, const int index, uiBut
return ui_but_find(region, ui_but_is_listrow_at_index, &data);
}
+static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
+{
+ return but->type == UI_BTYPE_TREEROW;
+}
+
+uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int x, const int y)
+{
+ return ui_but_find_mouse_over_ex(region, x, y, false, ui_but_is_treerow, NULL);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 7419f21cbc6..b199ce9562e 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -26,6 +26,8 @@
#include <memory>
#include <variant>
+#include "DNA_screen_types.h"
+
#include "BLI_listbase.h"
#include "interface_intern.h"
@@ -77,6 +79,21 @@ void ui_block_free_views(uiBlock *block)
}
}
+/**
+ * \param x, y: Coordinate to find a tree-row item at, in window space.
+ */
+uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region,
+ const int x,
+ const int y)
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, x, y);
+ if (!tree_row_but) {
+ return nullptr;
+ }
+
+ return tree_row_but->tree_item;
+}
+
static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view)
{
/* First get the idname the of the view we're looking for. */
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index 16499065019..0ea15a2a5bb 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -20,6 +20,8 @@
#include "DNA_userdef_types.h"
+#include "BLT_translation.h"
+
#include "interface_intern.h"
#include "UI_interface.h"
@@ -139,6 +141,24 @@ void AbstractTreeViewItem::on_activate()
/* Do nothing by default. */
}
+bool AbstractTreeViewItem::on_drop(const wmDrag & /*drag*/)
+{
+ /* Do nothing by default. */
+ return false;
+}
+
+bool AbstractTreeViewItem::can_drop(const wmDrag & /*drag*/) const
+{
+ return false;
+}
+
+std::string AbstractTreeViewItem::drop_tooltip(const bContext & /*C*/,
+ const wmDrag & /*drag*/,
+ const wmEvent & /*event*/) const
+{
+ return TIP_("Drop into/onto tree item");
+}
+
void AbstractTreeViewItem::update_from_old(const AbstractTreeViewItem &old)
{
is_open_ = old.is_open_;
@@ -327,3 +347,35 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
return a.matches(b);
}
+
+bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_, const wmDrag *drag)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return item.can_drop(*drag);
+}
+
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_,
+ const bContext *C,
+ const wmDrag *drag,
+ const wmEvent *event)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
+ return BLI_strdup(item.drop_tooltip(*C, *drag, *event).c_str());
+}
+
+/**
+ * Let a tree-view item handle a drop event.
+ * \return True if the drop was handled by the tree-view item.
+ */
+bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const ListBase *drags)
+{
+ AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
+
+ LISTBASE_FOREACH (const wmDrag *, drag, drags) {
+ if (item.can_drop(*drag)) {
+ return item.on_drop(*drag);
+ }
+ }
+
+ return false;
+}
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index d791c0717be..833c9accf95 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1699,6 +1699,9 @@ static void ed_default_handlers(
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "User Interface", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
+ ListBase *dropboxes = WM_dropboxmap_find("User Interface", 0, 0);
+ WM_event_add_dropbox_handler(handlers, dropboxes);
+
/* user interface widgets */
UI_region_handlers_add(handlers);
}
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index b3b3eafb6e7..3da283089c5 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -177,6 +177,7 @@ void ED_spacemacros_init(void)
ED_operatormacros_gpencil();
/* Register dropboxes (can use macros). */
+ ED_dropboxes_ui();
const ListBase *spacetypes = BKE_spacetypes_list();
LISTBASE_FOREACH (const SpaceType *, type, spacetypes) {
if (type->dropboxes) {