Changeset View
Changeset View
Standalone View
Standalone View
source/blender/windowmanager/intern/wm_dragdrop.c
| Show All 37 Lines | |||||
| #include "BIF_glutil.h" | #include "BIF_glutil.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_idtype.h" | #include "BKE_idtype.h" | ||||
| #include "BKE_lib_id.h" | #include "BKE_lib_id.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_screen.h" | |||||
| #include "GHOST_C-api.h" | |||||
| #include "BLO_readfile.h" | #include "BLO_readfile.h" | ||||
| #include "ED_asset.h" | #include "ED_asset.h" | ||||
| #include "GPU_shader.h" | #include "GPU_shader.h" | ||||
| #include "GPU_state.h" | #include "GPU_state.h" | ||||
| #include "GPU_viewport.h" | #include "GPU_viewport.h" | ||||
| #include "IMB_imbuf_types.h" | #include "IMB_imbuf_types.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_interface_icons.h" | #include "UI_interface_icons.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "wm_event_system.h" | #include "wm_event_system.h" | ||||
| #include "wm_window.h" | |||||
| /* ****************************************************** */ | /* ****************************************************** */ | ||||
| static ListBase dropboxes = {NULL, NULL}; | static ListBase dropboxes = {NULL, NULL}; | ||||
| static void wm_drag_free_asset_data(wmDragAsset **asset_data); | static void wm_drag_free_asset_data(wmDragAsset **asset_data); | ||||
| /* drop box maps are stored global for now */ | /* drop box maps are stored global for now */ | ||||
| ▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | void WM_drag_data_free(int dragtype, void *poin) | ||||
| } | } | ||||
| else { | else { | ||||
| MEM_freeN(poin); | MEM_freeN(poin); | ||||
| } | } | ||||
| } | } | ||||
| void WM_drag_free(wmDrag *drag) | void WM_drag_free(wmDrag *drag) | ||||
| { | { | ||||
| if (drag->dropbox && drag->dropbox->draw_deactivate) { | |||||
| drag->dropbox->draw_deactivate(drag->dropbox, drag); | |||||
| } | |||||
| if (drag->flags & WM_DRAG_FREE_DATA) { | if (drag->flags & WM_DRAG_FREE_DATA) { | ||||
| WM_drag_data_free(drag->type, drag->poin); | WM_drag_data_free(drag->type, drag->poin); | ||||
| } | } | ||||
| BLI_freelistN(&drag->ids); | BLI_freelistN(&drag->ids); | ||||
| LISTBASE_FOREACH_MUTABLE (wmDragAssetListItem *, asset_item, &drag->asset_items) { | LISTBASE_FOREACH_MUTABLE (wmDragAssetListItem *, asset_item, &drag->asset_items) { | ||||
| if (asset_item->is_external) { | if (asset_item->is_external) { | ||||
| wm_drag_free_asset_data(&asset_item->asset_data.external_info); | wm_drag_free_asset_data(&asset_item->asset_data.external_info); | ||||
| } | } | ||||
| BLI_freelinkN(&drag->asset_items, asset_item); | BLI_freelinkN(&drag->asset_items, asset_item); | ||||
| } | } | ||||
| MEM_freeN(drag); | MEM_freeN(drag); | ||||
| } | } | ||||
| void WM_drag_free_list(struct ListBase *lb) | void WM_drag_free_list(struct ListBase *lb) | ||||
| { | { | ||||
| wmDrag *drag; | wmDrag *drag; | ||||
| while ((drag = BLI_pophead(lb))) { | while ((drag = BLI_pophead(lb))) { | ||||
| WM_drag_free(drag); | WM_drag_free(drag); | ||||
| } | } | ||||
| } | } | ||||
| 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; | char *tooltip = NULL; | ||||
| if (drop->tooltip) { | if (drop->tooltip) { | ||||
| tooltip = drop->tooltip(C, drag, event, drop); | tooltip = drop->tooltip(C, drag, xy, drop); | ||||
| } | } | ||||
| if (!tooltip) { | if (!tooltip) { | ||||
| tooltip = BLI_strdup(WM_operatortype_name(drop->ot, drop->ptr)); | tooltip = BLI_strdup(WM_operatortype_name(drop->ot, drop->ptr)); | ||||
| } | } | ||||
| /* XXX Doing translation here might not be ideal, but later we have no more | /* XXX Doing translation here might not be ideal, but later we have no more | ||||
| * access to ot (and hence op context)... */ | * access to ot (and hence op context)... */ | ||||
| return tooltip; | return tooltip; | ||||
| } | } | ||||
| Show All 15 Lines | if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* return active operator tooltip/name when mouse is in box */ | /* 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); | wmWindow *win = CTX_wm_window(C); | ||||
| wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event); | wmDropBox *drop = dropbox_active(C, &win->handlers, drag, event); | ||||
| if (!drop) { | if (!drop) { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| drop = dropbox_active(C, &area->handlers, drag, event); | drop = dropbox_active(C, &area->handlers, drag, event); | ||||
| } | } | ||||
| if (!drop) { | if (!drop) { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| drop = dropbox_active(C, ®ion->handlers, drag, event); | drop = dropbox_active(C, ®ion->handlers, drag, event); | ||||
| } | } | ||||
| if (drop) { | return drop; | ||||
| return dropbox_tooltip(C, drag, event, drop); | |||||
| } | |||||
| return NULL; | |||||
| } | } | ||||
| static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event) | static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| const int winsize_x = WM_window_pixels_x(win); | const int winsize_x = WM_window_pixels_x(win); | ||||
| const int winsize_y = WM_window_pixels_y(win); | const int winsize_y = WM_window_pixels_y(win); | ||||
| /* for multiwin drags, we only do this if mouse inside */ | /* for multiwin drags, we only do this if mouse inside */ | ||||
| if (event->xy[0] < 0 || event->xy[1] < 0 || event->xy[0] > winsize_x || | if (event->xy[0] < 0 || event->xy[1] < 0 || event->xy[0] > winsize_x || | ||||
| event->xy[1] > winsize_y) { | event->xy[1] > winsize_y) { | ||||
| return; | return; | ||||
| } | } | ||||
| drag->tooltip[0] = 0; | wmDropBox *drop_prev = drag->dropbox; | ||||
| wmDropBox *drop = wm_dropbox_active(C, drag, event); | |||||
| /* check buttons (XXX todo rna and value) */ | if (drop != drop_prev) { | ||||
| if (UI_but_active_drop_name(C)) { | if (drop_prev && drop_prev->draw_deactivate) { | ||||
| BLI_strncpy(drag->tooltip, IFACE_("Paste name"), sizeof(drag->tooltip)); | drop_prev->draw_deactivate(drop_prev, drag); | ||||
| BLI_assert(drop_prev->draw_data == NULL); | |||||
| } | } | ||||
| else { | if (drop && drop->draw_activate) { | ||||
| char *tooltip = wm_dropbox_active(C, drag, event); | drop->draw_activate(drop, drag); | ||||
| if (tooltip) { | |||||
| BLI_strncpy(drag->tooltip, tooltip, sizeof(drag->tooltip)); | |||||
| MEM_freeN(tooltip); | |||||
| // WM_cursor_modal_set(win, WM_CURSOR_COPY); | |||||
| } | } | ||||
| // else | drag->dropbox = drop; | ||||
| // WM_cursor_modal_restore(win); | |||||
| /* unsure about cursor type, feels to be too much */ | |||||
| } | } | ||||
| } | } | ||||
| /* called in inner handler loop, region context */ | /* called in inner handler loop, region context */ | ||||
| void wm_drags_check_ops(bContext *C, const wmEvent *event) | void wm_drags_check_ops(bContext *C, const wmEvent *event) | ||||
| { | { | ||||
| wmWindowManager *wm = CTX_wm_manager(C); | wmWindowManager *wm = CTX_wm_manager(C); | ||||
| ▲ Show 20 Lines • Show All 280 Lines • ▼ Show 20 Lines | switch (drag->type) { | ||||
| } | } | ||||
| case WM_DRAG_PATH: | case WM_DRAG_PATH: | ||||
| case WM_DRAG_NAME: | case WM_DRAG_NAME: | ||||
| return drag->path; | return drag->path; | ||||
| } | } | ||||
| return ""; | return ""; | ||||
| } | } | ||||
| static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2) | static void wm_drag_draw_icon_fn(bContext *UNUSED(C), | ||||
| { | wmWindow *UNUSED(win), | ||||
| if (rect->xmin > x1) { | wmDrag *drag, | ||||
| rect->xmin = x1; | const int xy[2]) | ||||
| } | |||||
| if (rect->xmax < x2) { | |||||
| rect->xmax = x2; | |||||
| } | |||||
| if (rect->ymin > y1) { | |||||
| rect->ymin = y1; | |||||
| } | |||||
| if (rect->ymax < y2) { | |||||
| rect->ymax = y2; | |||||
| } | |||||
| } | |||||
| /* called in wm_draw.c */ | |||||
| /* if rect set, do not draw */ | |||||
| void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) | |||||
| { | { | ||||
| const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; | |||||
| wmWindowManager *wm = CTX_wm_manager(C); | |||||
| const int winsize_y = WM_window_pixels_y(win); | |||||
| int cursorx = win->eventstate->xy[0]; | |||||
| int cursory = win->eventstate->xy[1]; | |||||
| if (rect) { | |||||
| rect->xmin = rect->xmax = cursorx; | |||||
| rect->ymin = rect->ymax = cursory; | |||||
| } | |||||
| /* 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; | |||||
| /* image or icon */ | |||||
| int x, y; | int x, y; | ||||
| if (drag->imb) { | if (drag->imb) { | ||||
| x = cursorx - drag->sx / 2; | x = xy[0] - drag->sx / 2; | ||||
| y = cursory - drag->sy / 2; | y = xy[1] - drag->sy / 2; | ||||
| if (rect) { | |||||
| drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy); | |||||
| } | |||||
| else { | |||||
| float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ | float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ | ||||
| IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); | IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); | ||||
| immDrawPixelsTexScaled(&state, | immDrawPixelsTexScaled(&state, | ||||
| x, | x, | ||||
| y, | y, | ||||
| drag->imb->x, | drag->imb->x, | ||||
| drag->imb->y, | drag->imb->y, | ||||
| GPU_RGBA8, | GPU_RGBA8, | ||||
| false, | false, | ||||
| drag->imb->rect, | drag->imb->rect, | ||||
| drag->scale, | drag->scale, | ||||
| drag->scale, | drag->scale, | ||||
| 1.0f, | 1.0f, | ||||
| 1.0f, | 1.0f, | ||||
| col); | col); | ||||
| } | } | ||||
| } | |||||
| else { | else { | ||||
| x = cursorx - 2 * padding; | int padding = 4 * UI_DPI_FAC; | ||||
| y = cursory - 2 * UI_DPI_FAC; | x = xy[0] - 2 * padding; | ||||
| y = xy[1] - 2 * UI_DPI_FAC; | |||||
| if (rect) { | const uchar text_col[] = {255, 255, 255, 255}; | ||||
| drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize); | |||||
| } | |||||
| else { | |||||
| UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); | UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false); | ||||
| } | } | ||||
| } | } | ||||
| /* item name */ | void WM_drag_draw_item_name_fn(bContext *UNUSED(C), | ||||
| if (drag->imb) { | wmWindow *UNUSED(win), | ||||
| x = cursorx - drag->sx / 2; | wmDrag *drag, | ||||
| y = cursory - drag->sy / 2 - iconsize; | const int xy[2]) | ||||
| { | |||||
| int x = xy[0] + 10 * UI_DPI_FAC; | |||||
| int y = xy[1] + 1 * UI_DPI_FAC; | |||||
| const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; | |||||
| const uchar text_col[] = {255, 255, 255, 255}; | |||||
| UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col); | |||||
| } | } | ||||
| else { | |||||
| x = cursorx + 10 * UI_DPI_FAC; | static void wm_drag_draw_tooltip_fn(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2]) | ||||
| y = cursory + 1 * UI_DPI_FAC; | { | ||||
| if (!CTX_wm_region(C)) { | |||||
| /* Some callbacks require the region. */ | |||||
| return; | |||||
| } | } | ||||
| int iconsize = UI_DPI_ICON_SIZE; | |||||
| int padding = 4 * UI_DPI_FAC; | |||||
| if (rect) { | char *tooltip = NULL; | ||||
| int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag)); | bool free_tooltip = false; | ||||
| drag_rect_minmax(rect, x, y, x + w, y + iconsize); | if (UI_but_active_drop_name(C)) { | ||||
| tooltip = IFACE_("Paste name"); | |||||
| } | } | ||||
| else { | else if (drag->dropbox) { | ||||
| UI_fontstyle_draw_simple(fstyle, x, y, WM_drag_get_item_name(drag), text_col); | tooltip = dropbox_tooltip(C, drag, xy, drag->dropbox); | ||||
| free_tooltip = true; | |||||
| } | } | ||||
| /* operator name with roundbox */ | if (tooltip) { | ||||
| if (drag->tooltip[0]) { | const int winsize_y = WM_window_pixels_y(win); | ||||
| int x, y; | |||||
| if (drag->imb) { | if (drag->imb) { | ||||
| x = cursorx - drag->sx / 2; | x = xy[0] - drag->sx / 2; | ||||
| if (cursory + drag->sy / 2 + padding + iconsize < winsize_y) { | if (xy[1] + drag->sy / 2 + padding + iconsize < winsize_y) { | ||||
| y = cursory + drag->sy / 2 + padding; | y = xy[1] + drag->sy / 2 + padding; | ||||
| } | } | ||||
| else { | else { | ||||
| y = cursory - drag->sy / 2 - padding - iconsize - padding - iconsize; | y = xy[1] - drag->sy / 2 - padding - iconsize - padding - iconsize; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| x = cursorx - 2 * padding; | x = xy[0] - 2 * padding; | ||||
| if (cursory + iconsize + iconsize < winsize_y) { | if (xy[1] + iconsize + iconsize < winsize_y) { | ||||
| y = (cursory + iconsize) + padding; | y = (xy[1] + iconsize) + padding; | ||||
| } | } | ||||
| else { | else { | ||||
| y = (cursory - iconsize) - padding; | y = (xy[1] - iconsize) - padding; | ||||
| } | } | ||||
| } | } | ||||
| if (rect) { | wm_drop_operator_draw(tooltip, x, y); | ||||
| int w = UI_fontstyle_string_width(fstyle, WM_drag_get_item_name(drag)); | if (free_tooltip) { | ||||
| drag_rect_minmax(rect, x, y, x + w, y + iconsize); | MEM_freeN(tooltip); | ||||
| } | |||||
| } | |||||
| } | |||||
| void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int xy[2]) | |||||
| { | |||||
| int xy_tmp[2] = {UNPACK2(xy)}; | |||||
| /* Image or icon. */ | |||||
| wm_drag_draw_icon_fn(C, win, drag, xy_tmp); | |||||
| /* Item name. */ | |||||
| if (drag->imb) { | |||||
| int iconsize = UI_DPI_ICON_SIZE; | |||||
| xy_tmp[0] = xy[0] - (drag->sx / 2) - 10 * UI_DPI_FAC; | |||||
| xy_tmp[1] = xy[1] - (drag->sy / 2) - iconsize - 1 * UI_DPI_FAC; | |||||
| } | |||||
| WM_drag_draw_item_name_fn(C, win, drag, xy_tmp); | |||||
| /* Operator name with roundbox. */ | |||||
| wm_drag_draw_tooltip_fn(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 { | else { | ||||
| wm_drop_operator_draw(drag->tooltip, x, y); | 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->dropbox && drag->dropbox->draw) { | |||||
| drag->dropbox->draw(C, win, drag, xy); | |||||
| continue; | |||||
| } | } | ||||
| WM_drag_draw_default_fn(C, win, drag, xy); | |||||
| } | } | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| CTX_wm_area_set(C, NULL); | |||||
| CTX_wm_region_set(C, NULL); | |||||
| } | } | ||||