From e8027ec2a0cac4b0e92d51a64ccc40fd3f190a20 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Mon, 25 Oct 2021 10:07:00 -0300 Subject: UI Drag Drop: allow customizable drawing No functional changes. This commit adds 3 callbacks for `wmDropBox` which allow custom drawing without affecting the internal dropbox API. Differential Revision: https://developer.blender.org/D12948 --- source/blender/editors/include/ED_object.h | 2 +- .../editors/interface/interface_dropboxes.cc | 5 +- source/blender/editors/object/object_relations.c | 4 +- .../editors/space_outliner/outliner_dragdrop.c | 8 +- source/blender/editors/space_view3d/space_view3d.c | 11 +- source/blender/windowmanager/WM_api.h | 4 + source/blender/windowmanager/WM_types.h | 21 +- source/blender/windowmanager/intern/wm_dragdrop.c | 262 ++++++++++++--------- source/blender/windowmanager/intern/wm_draw.c | 4 +- source/blender/windowmanager/wm_event_system.h | 2 +- 10 files changed, 188 insertions(+), 135 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 083d167c573..458ce57ab86 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -202,7 +202,7 @@ void ED_object_parent(struct Object *ob, const char *substr); char *ED_object_ot_drop_named_material_tooltip(struct bContext *C, struct PointerRNA *properties, - const struct wmEvent *event); + const int mval[2]); /* bitflags for enter/exit editmode */ enum { diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index ae626080a9a..1cc06db3a8c 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -40,12 +40,11 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve static char *ui_tree_view_drop_tooltip(bContext *C, wmDrag *drag, - const wmEvent *event, + const int xy[2], wmDropBox *UNUSED(drop)) { const ARegion *region = CTX_wm_region(C); - const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, - event->xy); + const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy); if (!hovered_tree_item) { return nullptr; } diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d81143d6081..a64510662d9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2589,10 +2589,10 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot) char *ED_object_ot_drop_named_material_tooltip(bContext *C, PointerRNA *properties, - const wmEvent *event) + const int mval[2]) { int mat_slot = 0; - Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot); + Object *ob = ED_view3d_give_material_slot_under_cursor(C, mval, &mat_slot); if (ob == NULL) { return BLI_strdup(""); } diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index a82f516b125..a391d032d7e 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -868,7 +868,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) static char *datastack_drop_tooltip(bContext *UNUSED(C), wmDrag *drag, - const wmEvent *UNUSED(event), + const int UNUSED(xy[2]), struct wmDropBox *UNUSED(drop)) { StackDropData *drop_data = drag->poin; @@ -1201,11 +1201,13 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event static char *collection_drop_tooltip(bContext *C, wmDrag *drag, - const wmEvent *event, + const int UNUSED(xy[2]), wmDropBox *UNUSED(drop)) { + wmWindowManager *wm = CTX_wm_manager(C); + const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL; CollectionDrop data; - if (!event->shift && collection_drop_init(C, drag, event, &data)) { + if (event && !event->shift && collection_drop_init(C, drag, event, &data)) { TreeElement *te = data.te; if (!data.from || event->ctrl) { return BLI_strdup(TIP_("Link inside Collection")); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 7999018a6b6..eb30d0987ab 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -532,12 +532,17 @@ static bool view3d_mat_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event static char *view3d_mat_drop_tooltip(bContext *C, wmDrag *drag, - const wmEvent *event, + const int xy[2], struct wmDropBox *drop) { const char *name = WM_drag_get_item_name(drag); + ARegion *region = CTX_wm_region(C); RNA_string_set(drop->ptr, "name", name); - return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, event); + int mval[2] = { + xy[0] - region->winrct.xmin, + xy[1] - region->winrct.ymin, + }; + return ED_object_ot_drop_named_material_tooltip(C, drop->ptr, mval); } static bool view3d_world_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -556,7 +561,7 @@ static bool view3d_object_data_drop_poll(bContext *C, wmDrag *drag, const wmEven static char *view3d_object_data_drop_tooltip(bContext *UNUSED(C), wmDrag *UNUSED(drag), - const wmEvent *UNUSED(event), + const int UNUSED(xy[2]), wmDropBox *UNUSED(drop)) { return BLI_strdup(TIP_("Create object instance from object-data")); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index eaf32c06aba..b4fe2f85b72 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -740,6 +740,10 @@ struct wmDropBox *WM_dropbox_add( void (*copy)(struct wmDrag *, struct wmDropBox *), void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *), WMDropboxTooltipFunc tooltip); +void WM_drag_draw_default_fn(struct bContext *C, + struct wmWindow *win, + struct wmDrag *drag, + const int xy[2]); ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid); /* ID drag and drop */ diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f4595869baf..bbfc9d53e44 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -1020,7 +1020,7 @@ typedef struct wmDragAssetListItem { typedef char *(*WMDropboxTooltipFunc)(struct bContext *, struct wmDrag *, - const struct wmEvent *event, + const int xy[2], struct wmDropBox *drop); typedef struct wmDrag { @@ -1038,8 +1038,11 @@ typedef struct wmDrag { float scale; int sx, sy; - /** If filled, draws operator tooltip/operator name. */ - char tooltip[200]; + /** Informs which dropbox is activated with the drag item. + * When this value changes, the #draw_activate and #draw_deactivate dropbox callbacks are + * triggered. + */ + struct wmDropBox *active_dropbox; unsigned int flags; /** List of wmDragIDs, all are guaranteed to have the same ID type. */ @@ -1067,6 +1070,18 @@ typedef struct wmDropBox { */ void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *); + /** Override the default drawing function. */ + void (*draw)(struct bContext *, struct wmWindow *, struct wmDrag *, const int *); + + /** Called when pool returns true the first time. */ + void (*draw_activate)(struct wmDropBox *, struct wmDrag *drag); + + /** Called when pool returns false the first time or when the drag event ends. */ + void (*draw_deactivate)(struct wmDropBox *, struct wmDrag *drag); + + /** Custom data for drawing. */ + void *draw_data; + /** Custom tooltip shown during dragging. */ WMDropboxTooltipFunc tooltip; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 9af90355a79..8495fa2a082 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -43,6 +43,9 @@ #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_screen.h" + +#include "GHOST_C-api.h" #include "BLO_readfile.h" @@ -63,6 +66,7 @@ #include "WM_api.h" #include "WM_types.h" #include "wm_event_system.h" +#include "wm_window.h" /* ****************************************************** */ @@ -229,6 +233,9 @@ void WM_drag_data_free(int dragtype, void *poin) void WM_drag_free(wmDrag *drag) { + if (drag->active_dropbox && drag->active_dropbox->draw_deactivate) { + drag->active_dropbox->draw_deactivate(drag->active_dropbox, drag); + } if (drag->flags & WM_DRAG_FREE_DATA) { WM_drag_data_free(drag->type, drag->poin); } @@ -250,11 +257,11 @@ void WM_drag_free_list(struct ListBase *lb) } } -static char *dropbox_tooltip(bContext *C, wmDrag *drag, const wmEvent *event, wmDropBox *drop) +static char *dropbox_tooltip(bContext *C, wmDrag *drag, const int xy[2], wmDropBox *drop) { char *tooltip = NULL; if (drop->tooltip) { - tooltip = drop->tooltip(C, drag, event, drop); + tooltip = drop->tooltip(C, drag, xy, drop); } if (!tooltip) { tooltip = BLI_strdup(WM_operatortype_name(drop->ot, drop->ptr)); @@ -286,7 +293,7 @@ static wmDropBox *dropbox_active(bContext *C, } /* return active operator tooltip/name when mouse is in box */ -static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event) +static wmDropBox *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event); @@ -298,10 +305,7 @@ static char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event) ARegion *region = CTX_wm_region(C); drop = dropbox_active(C, ®ion->handlers, drag, event); } - if (drop) { - return dropbox_tooltip(C, drag, event, drop); - } - return NULL; + return drop; } static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event) @@ -316,23 +320,17 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *e return; } - drag->tooltip[0] = 0; - - /* check buttons (XXX todo rna and value) */ - if (UI_but_active_drop_name(C)) { - BLI_strncpy(drag->tooltip, IFACE_("Paste name"), sizeof(drag->tooltip)); - } - else { - char *tooltip = wm_dropbox_active(C, drag, event); - - if (tooltip) { - BLI_strncpy(drag->tooltip, tooltip, sizeof(drag->tooltip)); - MEM_freeN(tooltip); - // WM_cursor_modal_set(win, WM_CURSOR_COPY); + wmDropBox *drop_prev = drag->active_dropbox; + wmDropBox *drop = wm_dropbox_active(C, drag, event); + if (drop != drop_prev) { + if (drop_prev && drop_prev->draw_deactivate) { + drop_prev->draw_deactivate(drop_prev, drag); + BLI_assert(drop_prev->draw_data == NULL); + } + if (drop && drop->draw_activate) { + drop->draw_activate(drop, drag); } - // else - // WM_cursor_modal_restore(win); - /* unsure about cursor type, feels to be too much */ + drag->active_dropbox = drop; } } @@ -629,132 +627,162 @@ const char *WM_drag_get_item_name(wmDrag *drag) return ""; } -static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2) +static void wm_drag_draw_icon(bContext *UNUSED(C), + wmWindow *UNUSED(win), + wmDrag *drag, + const int xy[2]) { - if (rect->xmin > x1) { - rect->xmin = x1; - } - if (rect->xmax < x2) { - rect->xmax = x2; + int x, y; + if (drag->imb) { + x = xy[0] - drag->sx / 2; + y = xy[1] - drag->sy / 2; + + float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ + IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + immDrawPixelsTexScaled(&state, + x, + y, + drag->imb->x, + drag->imb->y, + GPU_RGBA8, + false, + drag->imb->rect, + drag->scale, + drag->scale, + 1.0f, + 1.0f, + col); } - if (rect->ymin > y1) { - rect->ymin = y1; - } - if (rect->ymax < y2) { - rect->ymax = y2; + else { + int padding = 4 * UI_DPI_FAC; + x = xy[0] - 2 * padding; + y = xy[1] - 2 * UI_DPI_FAC; + + const uchar text_col[] = {255, 255, 255, 255}; + UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); } } -/* called in wm_draw.c */ -/* if rect set, do not draw */ -void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) +static void wm_drag_draw_item_name(wmDrag *drag, const int x, const int y) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - wmWindowManager *wm = CTX_wm_manager(C); - const int winsize_y = WM_window_pixels_y(win); + const uchar text_col[] = {255, 255, 255, 255}; + UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col); +} - int cursorx = win->eventstate->xy[0]; - int cursory = win->eventstate->xy[1]; - if (rect) { - rect->xmin = rect->xmax = cursorx; - rect->ymin = rect->ymax = cursory; +static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2]) +{ + if (!CTX_wm_region(C)) { + /* Some callbacks require the region. */ + return; } + int iconsize = UI_DPI_ICON_SIZE; + int padding = 4 * UI_DPI_FAC; - /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */ - GPU_blend(GPU_BLEND_ALPHA); - LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) { - const uchar text_col[] = {255, 255, 255, 255}; - int iconsize = UI_DPI_ICON_SIZE; - int padding = 4 * UI_DPI_FAC; + char *tooltip = NULL; + bool free_tooltip = false; + if (UI_but_active_drop_name(C)) { + tooltip = IFACE_("Paste name"); + } + else if (drag->active_dropbox) { + tooltip = dropbox_tooltip(C, drag, xy, drag->active_dropbox); + free_tooltip = true; + } - /* image or icon */ + if (tooltip) { + const int winsize_y = WM_window_pixels_y(win); int x, y; if (drag->imb) { - x = cursorx - drag->sx / 2; - y = cursory - drag->sy / 2; + x = xy[0] - drag->sx / 2; - if (rect) { - drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy); + if (xy[1] + drag->sy / 2 + padding + iconsize < winsize_y) { + y = xy[1] + drag->sy / 2 + padding; } else { - float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTexScaled(&state, - x, - y, - drag->imb->x, - drag->imb->y, - GPU_RGBA8, - false, - drag->imb->rect, - drag->scale, - drag->scale, - 1.0f, - 1.0f, - col); + y = xy[1] - drag->sy / 2 - padding - iconsize - padding - iconsize; } } else { - x = cursorx - 2 * padding; - y = cursory - 2 * UI_DPI_FAC; + x = xy[0] - 2 * padding; - if (rect) { - drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize); + if (xy[1] + iconsize + iconsize < winsize_y) { + y = (xy[1] + iconsize) + padding; } else { - UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); + y = (xy[1] - iconsize) - padding; } } - /* item name */ - if (drag->imb) { - x = cursorx - drag->sx / 2; - y = cursory - drag->sy / 2 - iconsize; - } - else { - x = cursorx + 10 * UI_DPI_FAC; - y = cursory + 1 * UI_DPI_FAC; + wm_drop_operator_draw(tooltip, x, y); + if (free_tooltip) { + MEM_freeN(tooltip); } + } +} - if (rect) { - int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag)); - drag_rect_minmax(rect, x, y, x + w, y + iconsize); - } - else { - UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col); - } +static void wm_drag_draw_default(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2]) +{ + int xy_tmp[2] = {UNPACK2(xy)}; - /* operator name with roundbox */ - if (drag->tooltip[0]) { - if (drag->imb) { - x = cursorx - drag->sx / 2; + /* Image or icon. */ + wm_drag_draw_icon(C, win, drag, xy_tmp); - if (cursory + drag->sy / 2 + padding + iconsize < winsize_y) { - y = cursory + drag->sy / 2 + padding; - } - else { - y = cursory - drag->sy / 2 - padding - iconsize - padding - iconsize; - } - } - else { - x = cursorx - 2 * padding; + /* Item name. */ + if (drag->imb) { + int iconsize = UI_DPI_ICON_SIZE; + xy_tmp[0] = xy[0] - (drag->sx / 2); + xy_tmp[1] = xy[1] - (drag->sy / 2) - iconsize; + } + else { + xy_tmp[0] = xy[0] + 10 * UI_DPI_FAC; + xy_tmp[1] = xy[1] + 1 * UI_DPI_FAC; + } + wm_drag_draw_item_name(drag, UNPACK2(xy_tmp)); - if (cursory + iconsize + iconsize < winsize_y) { - y = (cursory + iconsize) + padding; - } - else { - y = (cursory - iconsize) - padding; - } - } + /* Operator name with roundbox. */ + wm_drag_draw_tooltip(C, win, drag, xy); +} - if (rect) { - int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag)); - drag_rect_minmax(rect, x, y, x + w, y + iconsize); - } - else { - wm_drop_operator_draw(drag->tooltip, x, y); - } +void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2]) +{ + wm_drag_draw_default(C, win, drag, xy); +} + +/* Called in #wm_draw_window_onscreen. */ +void wm_drags_draw(bContext *C, wmWindow *win) +{ + int xy[2]; + if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) { + wm_cursor_position_get(win, &xy[0], &xy[1]); + } + else { + xy[0] = win->eventstate->xy[0]; + xy[1] = win->eventstate->xy[1]; + } + + /* Set a region. It is used in the `UI_but_active_drop_name`. */ + bScreen *screen = CTX_wm_screen(C); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy)); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, UNPACK2(xy)); + if (region) { + BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C)); + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + } + + wmWindowManager *wm = CTX_wm_manager(C); + + /* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */ + GPU_blend(GPU_BLEND_ALPHA); + LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) { + if (drag->active_dropbox && drag->active_dropbox->draw) { + drag->active_dropbox->draw(C, win, drag, xy); + continue; } + + wm_drag_draw_default(C, win, drag, xy); } GPU_blend(GPU_BLEND_NONE); + CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, NULL); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index b5e81528e2b..8acce240046 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -856,9 +856,9 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) wm_gesture_draw(win); } - /* needs pixel coords in screen */ + /* Needs pixel coords in screen. */ if (wm->drags.first) { - wm_drags_draw(C, win, NULL); + wm_drags_draw(C, win); } GPU_debug_group_end(); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index d1eb10787e2..dfc8c578420 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -173,7 +173,7 @@ void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTab /* wm_dropbox.c */ void wm_dropbox_free(void); void wm_drags_check_ops(bContext *C, const wmEvent *event); -void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect); +void wm_drags_draw(bContext *C, wmWindow *win); #ifdef __cplusplus } -- cgit v1.2.3