Asset System: Support dragging assets and appending on drop

For the Asset Browser, it needs to be possible to drag assets into various
editors, which may not come from the current .blend file. In other words, the
dragging needs to work with just the asset metadata, without direct access to
the data-block itself.

Idea is simple: When dragging an asset, store the source file-path and
data-block name and when dropping, append the data-block. It uses existing drop
operators, but the function to get the dropped data-block is replaced with one
that returns the local data-block, or, in case of an external asset, appends
the data-block first.

The drop operators need to be adjusted to use this new function that respects
assets. With this patch it only works for dragging assets into the 3D view.

Note that I expect this to be a short-lived change. A refactor like D4071 is
needed to make the drag & drop system more future proof for assets and other
use cases.

Part of the first Asset Browser milestone. Check the #asset_browser_milestone_1
project milestone on developer.blender.org.

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

Reviewed by: Bastien Montagne, Brecht Van Lommel
This commit is contained in:
Julian Eisel
2020-12-14 13:31:55 +01:00
parent 9363132c86
commit b5d778a7d4
11 changed files with 181 additions and 58 deletions

View File

@@ -727,6 +727,13 @@ void UI_block_translate(uiBlock *block, int x, int y);
int UI_but_return_value_get(uiBut *but);
void UI_but_drag_set_id(uiBut *but, struct ID *id);
void UI_but_drag_set_asset(uiBut *but,
const char *name,
const char *path,
int id_type,
int icon,
struct ImBuf *imb,
float scale);
void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr);
void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free);
void UI_but_drag_set_name(uiBut *but, const char *name);

View File

@@ -3352,7 +3352,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
}
if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_freeN(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
}
ui_but_extra_operator_icons_free(but);
@@ -6098,17 +6098,42 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
{
but->dragtype = WM_DRAG_ID;
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_SAFE_FREE(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
}
but->dragpoin = (void *)id;
}
void UI_but_drag_set_asset(uiBut *but,
const char *name,
const char *path,
int id_type,
int icon,
struct ImBuf *imb,
float scale)
{
wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset");
BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name));
asset_drag->path = path;
asset_drag->id_type = id_type;
but->dragtype = WM_DRAG_ASSET;
ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
WM_drag_data_free(but->dragtype, but->dragpoin);
}
but->dragpoin = asset_drag;
but->dragflag |= UI_BUT_DRAGPOIN_FREE;
but->imb = imb;
but->imb_scale = scale;
}
void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
{
but->dragtype = WM_DRAG_RNA;
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_SAFE_FREE(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
}
but->dragpoin = (void *)ptr;
@@ -6118,7 +6143,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
{
but->dragtype = WM_DRAG_PATH;
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_SAFE_FREE(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
}
but->dragpoin = (void *)path;
@@ -6131,7 +6156,7 @@ void UI_but_drag_set_name(uiBut *but, const char *name)
{
but->dragtype = WM_DRAG_NAME;
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_SAFE_FREE(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
}
but->dragpoin = (void *)name;
@@ -6149,7 +6174,7 @@ void UI_but_drag_set_image(
but->dragtype = WM_DRAG_PATH;
ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
MEM_SAFE_FREE(but->dragpoin);
WM_drag_data_free(but->dragtype, but->dragpoin);
but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
}
but->dragpoin = (void *)path;

View File

@@ -1987,6 +1987,8 @@ static bool ui_but_drag_init(bContext *C,
else {
wmDrag *drag = WM_event_start_drag(
C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP);
/* wmDrag has ownership over dragpoin now, stop messing with it. */
but->dragpoin = NULL;
if (but->imb) {
WM_event_drag_image(drag,
@@ -2259,10 +2261,11 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */
LISTBASE_FOREACH (wmDrag *, wmd, drags) {
/* TODO asset dropping. */
if (wmd->type == WM_DRAG_ID) {
/* align these types with UI_but_active_drop_name */
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
ID *id = WM_drag_ID(wmd, 0);
ID *id = WM_drag_get_local_ID(wmd, 0);
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);

View File

@@ -164,12 +164,12 @@ static bool id_drop_poll(bContext *UNUSED(C),
const wmEvent *UNUSED(event),
const char **UNUSED(tooltip))
{
return WM_drag_ID(drag, 0) != NULL;
return WM_drag_get_local_ID(drag, 0) != NULL;
}
static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
/* copy drag path to properties */
char *text = RNA_path_full_ID_py(G_MAIN, id);

View File

@@ -645,7 +645,7 @@ static bool node_ima_drop_poll(bContext *UNUSED(C),
/* rule might not work? */
return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE));
}
return WM_drag_ID(drag, ID_IM) != NULL;
return WM_drag_get_local_ID(drag, ID_IM) != NULL;
}
static bool node_mask_drop_poll(bContext *UNUSED(C),
@@ -653,19 +653,19 @@ static bool node_mask_drop_poll(bContext *UNUSED(C),
const wmEvent *UNUSED(event),
const char **UNUSED(r_tooltip))
{
return WM_drag_ID(drag, ID_MSK) != NULL;
return WM_drag_get_local_ID(drag, ID_MSK) != NULL;
}
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);

View File

@@ -333,7 +333,7 @@ static bool parent_drop_poll(bContext *C,
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
}
Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB);
Object *potential_child = (Object *)WM_drag_get_local_ID(drag, ID_OB);
if (!potential_child) {
return false;
}
@@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
Object *par = (Object *)tselem->id;
Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
if (ELEM(NULL, ob, par)) {
return OPERATOR_CANCELLED;
@@ -473,7 +473,7 @@ static bool parent_clear_poll(bContext *C,
}
}
Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
if (!ob) {
return false;
}
@@ -552,7 +552,7 @@ static bool scene_drop_poll(bContext *C,
const char **UNUSED(r_tooltip))
{
/* Ensure item under cursor is valid drop target */
Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
}
@@ -560,7 +560,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
{
Main *bmain = CTX_data_main(C);
Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE);
Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
return OPERATOR_CANCELLED;
@@ -620,7 +620,7 @@ static bool material_drop_poll(bContext *C,
const char **UNUSED(r_tooltip))
{
/* Ensure item under cursor is valid drop target */
Material *ma = (Material *)WM_drag_ID(drag, ID_MA);
Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA);
return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
}
@@ -628,7 +628,7 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
{
Main *bmain = CTX_data_main(C);
Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA);
Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA);
if (ELEM(NULL, ob, ma)) {
return OPERATOR_CANCELLED;
@@ -1461,14 +1461,14 @@ static int outliner_item_drag_drop_invoke(bContext *C,
parent = scene->master_collection;
}
WM_drag_add_ID(drag, id, &parent->id);
WM_drag_add_local_ID(drag, id, &parent->id);
}
BLI_freelistN(&selected.selected_array);
}
else {
/* Add single ID. */
WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent);
}
ED_outliner_select_sync_from_outliner(C, space_outliner);

View File

@@ -357,7 +357,7 @@ static bool text_drop_paste_poll(bContext *UNUSED(C),
static void text_drop_paste(wmDrag *drag, wmDropBox *drop)
{
char *text;
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
/* copy drag path to properties */
text = RNA_path_full_ID_py(G_MAIN, id);

View File

@@ -461,6 +461,12 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *region)
ED_view3d_stop_render_preview(wm, region);
}
static bool view3d_drop_in_main_region_poll(bContext *C, const wmEvent *event)
{
ScrArea *area = CTX_wm_area(C);
return ED_region_overlap_isect_any_xy(area, &event->x) == false;
}
static ID *view3d_drop_id_in_main_region_poll_id(bContext *C,
wmDrag *drag,
const wmEvent *event,
@@ -470,7 +476,7 @@ static ID *view3d_drop_id_in_main_region_poll_id(bContext *C,
if (ED_region_overlap_isect_any_xy(area, &event->x)) {
return NULL;
}
return WM_drag_ID(drag, id_type);
return view3d_drop_in_main_region_poll(C, event) ? WM_drag_get_local_ID(drag, id_type) : NULL;
}
static bool view3d_drop_id_in_main_region_poll(bContext *C,
@@ -478,7 +484,11 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C,
const wmEvent *event,
ID_Type id_type)
{
return (view3d_drop_id_in_main_region_poll_id(C, drag, event, id_type) != NULL);
if (!view3d_drop_in_main_region_poll(C, event)) {
return false;
}
return WM_drag_get_local_ID(drag, id_type) || WM_drag_get_asset_data(drag, id_type);
}
static bool view3d_ob_drop_poll(bContext *C,
@@ -533,7 +543,7 @@ static bool view3d_ima_drop_poll(bContext *C,
return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE));
}
return WM_drag_ID(drag, ID_IM) != NULL;
return WM_drag_get_local_ID(drag, ID_IM) || WM_drag_get_asset_data(drag, ID_IM);
}
static bool view3d_ima_bg_is_camera_view(bContext *C)
@@ -596,14 +606,14 @@ static bool view3d_volume_drop_poll(bContext *UNUSED(C),
static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, ID_OB);
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, ID_GR);
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR);
drop->opcontext = WM_OP_EXEC_DEFAULT;
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -611,14 +621,14 @@ static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop)
static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
RNA_string_set(drop->ptr, "name", id->name + 2);
RNA_enum_set(drop->ptr, "type", GS(id->name));
@@ -626,7 +636,7 @@ static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop)
static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0);
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);

View File

@@ -671,6 +671,7 @@ struct wmDrag *WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy);
void WM_drag_free(struct wmDrag *drag);
void WM_drag_data_free(int dragtype, void *poin);
void WM_drag_free_list(struct ListBase *lb);
struct wmDropBox *WM_dropbox_add(
@@ -681,9 +682,12 @@ struct wmDropBox *WM_dropbox_add(
ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid);
/* ID drag and drop */
void WM_drag_add_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_ID_from_event(const struct wmEvent *event, short idcode);
void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent);
struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode);
struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode);
struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode);
struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode);
/* Set OpenGL viewport and scissor */
void wmViewport(const struct rcti *winrct);

View File

@@ -836,12 +836,13 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata
/* *************** Drag and drop *************** */
#define WM_DRAG_ID 0
#define WM_DRAG_RNA 1
#define WM_DRAG_PATH 2
#define WM_DRAG_NAME 3
#define WM_DRAG_VALUE 4
#define WM_DRAG_COLOR 5
#define WM_DRAG_DATASTACK 6
#define WM_DRAG_ASSET 1
#define WM_DRAG_RNA 2
#define WM_DRAG_PATH 3
#define WM_DRAG_NAME 4
#define WM_DRAG_VALUE 5
#define WM_DRAG_COLOR 6
#define WM_DRAG_DATASTACK 7
typedef enum wmDragFlags {
WM_DRAG_NOP = 0,
@@ -856,6 +857,13 @@ typedef struct wmDragID {
struct ID *from_parent;
} wmDragID;
typedef struct wmDragAsset {
char name[64]; /* MAX_NAME */
/* Always freed. */
const char *path;
int id_type;
} wmDragAsset;
typedef struct wmDrag {
struct wmDrag *next, *prev;

View File

@@ -37,6 +37,7 @@
#include "BIF_glutil.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "GPU_shader.h"
@@ -146,16 +147,23 @@ wmDrag *WM_event_start_drag(
drag->flags = flags;
drag->icon = icon;
drag->type = type;
if (type == WM_DRAG_PATH) {
BLI_strncpy(drag->path, poin, FILE_MAX);
}
else if (type == WM_DRAG_ID) {
if (poin) {
WM_drag_add_ID(drag, poin, NULL);
}
}
else {
drag->poin = poin;
switch (type) {
case WM_DRAG_PATH:
BLI_strncpy(drag->path, poin, FILE_MAX);
break;
case WM_DRAG_ID:
if (poin) {
WM_drag_add_local_ID(drag, poin, NULL);
}
break;
case WM_DRAG_ASSET:
/* Move ownership of poin to wmDrag. */
drag->poin = poin;
drag->flags |= WM_DRAG_FREE_DATA;
break;
default:
drag->poin = poin;
break;
}
drag->value = value;
@@ -170,12 +178,26 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
drag->sy = sy;
}
void WM_drag_free(wmDrag *drag)
void WM_drag_data_free(int dragtype, void *poin)
{
if ((drag->flags & WM_DRAG_FREE_DATA) && drag->poin) {
MEM_freeN(drag->poin);
/* Don't require all the callers to have a NULL-check, just allow passing NULL. */
if (!poin) {
return;
}
/* Not too nice, could become a callback. */
if (dragtype == WM_DRAG_ASSET) {
wmDragAsset *asset_drag = poin;
MEM_freeN((void *)asset_drag->path);
}
MEM_freeN(poin);
}
void WM_drag_free(wmDrag *drag)
{
if (drag->flags & WM_DRAG_FREE_DATA) {
WM_drag_data_free(drag->type, drag->poin);
}
BLI_freelistN(&drag->ids);
MEM_freeN(drag);
}
@@ -279,7 +301,7 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
/* ************** IDs ***************** */
void WM_drag_add_ID(wmDrag *drag, ID *id, ID *from_parent)
void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent)
{
/* Don't drag the same ID twice. */
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
@@ -302,7 +324,7 @@ void WM_drag_add_ID(wmDrag *drag, ID *id, ID *from_parent)
BLI_addtail(&drag->ids, drag_id);
}
ID *WM_drag_ID(const wmDrag *drag, short idcode)
ID *WM_drag_get_local_ID(const wmDrag *drag, short idcode)
{
if (drag->type != WM_DRAG_ID) {
return NULL;
@@ -317,14 +339,54 @@ ID *WM_drag_ID(const wmDrag *drag, short idcode)
return (idcode == 0 || GS(id->name) == idcode) ? id : NULL;
}
ID *WM_drag_ID_from_event(const wmEvent *event, short idcode)
ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode)
{
if (event->custom != EVT_DATA_DRAGDROP) {
return NULL;
}
ListBase *lb = event->customdata;
return WM_drag_ID(lb->first, idcode);
return WM_drag_get_local_ID(lb->first, idcode);
}
wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode)
{
if (drag->type != WM_DRAG_ASSET) {
return NULL;
}
wmDragAsset *asset_drag = drag->poin;
return (idcode == 0 || asset_drag->id_type == idcode) ? asset_drag : NULL;
}
static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag)
{
/* Append only for now, wmDragAsset could have a `link` bool. */
return WM_file_append_datablock(
G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name);
}
/**
* When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append
* that depending on what was chosen by the drag-box (currently append only in fact).
*/
ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode)
{
if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) {
return NULL;
}
if (drag->type == WM_DRAG_ID) {
return WM_drag_get_local_ID(drag, idcode);
}
wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, idcode);
if (!asset_drag) {
return NULL;
}
/* Link/append the asset. */
return wm_drag_asset_id_import(asset_drag);
}
/* ************** draw ***************** */
@@ -342,7 +404,7 @@ static const char *wm_drag_name(wmDrag *drag)
{
switch (drag->type) {
case WM_DRAG_ID: {
ID *id = WM_drag_ID(drag, 0);
ID *id = WM_drag_get_local_ID(drag, 0);
bool single = (BLI_listbase_count_at_most(&drag->ids, 2) == 1);
if (single) {
@@ -353,6 +415,10 @@ static const char *wm_drag_name(wmDrag *drag)
}
break;
}
case WM_DRAG_ASSET: {
const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0);
return asset_drag->name;
}
case WM_DRAG_PATH:
case WM_DRAG_NAME:
return drag->path;