diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_dragdrop.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_dragdrop.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c new file mode 100644 index 00000000000..d976c42bb8c --- /dev/null +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -0,0 +1,370 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2010 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "string.h" + +#include "DNA_windowmanager_types.h" +#include "DNA_screen_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "BKE_blender.h" +#include "BKE_context.h" +#include "BKE_idprop.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_global.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_event_system.h" +#include "wm.h" + +#include "RNA_types.h" + +/* ****************************************************** */ + +static ListBase dropboxes= {NULL, NULL}; + +/* drop box maps are stored global for now */ +/* these are part of blender's UI/space specs, and not like keymaps */ +/* when editors become configurable, they can add own dropbox definitions */ + +typedef struct wmDropBoxMap { + struct wmDropBoxMap *next, *prev; + + ListBase dropboxes; + short spaceid, regionid; + char idname[KMAP_MAX_NAME]; + +} wmDropBoxMap; + +ListBase *WM_dropboxmap_find(char *idname, int spaceid, int regionid) +{ + wmDropBoxMap *dm; + + for(dm= dropboxes.first; dm; dm= dm->next) + if(dm->spaceid==spaceid && dm->regionid==regionid) + if(0==strncmp(idname, dm->idname, KMAP_MAX_NAME)) + return &dm->dropboxes; + + dm= MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list"); + BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME); + dm->spaceid= spaceid; + dm->regionid= regionid; + BLI_addtail(&dropboxes, dm); + + return &dm->dropboxes; +} + + + +wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(bContext *, wmDrag *, wmEvent *), + void (*copy)(wmDrag *, wmDropBox *)) +{ + wmDropBox *drop= MEM_callocN(sizeof(wmDropBox), "wmDropBox"); + + drop->poll= poll; + drop->copy= copy; + drop->ot= WM_operatortype_find(idname, 0); + + if(drop->ot==NULL) { + MEM_freeN(drop); + printf("Error: dropbox with unknown operator: %s\n", idname); + return NULL; + } + WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname); + + BLI_addtail(lb, drop); + + return drop; +} + +void wm_dropbox_free(void) +{ + wmDropBoxMap *dm; + + for(dm= dropboxes.first; dm; dm= dm->next) { + wmDropBox *drop; + + for(drop= dm->dropboxes.first; drop; drop= drop->next) { + if(drop->ptr) { + WM_operator_properties_free(drop->ptr); + MEM_freeN(drop->ptr); + } + } + BLI_freelistN(&dm->dropboxes); + } + + BLI_freelistN(&dropboxes); +} + +/* *********************************** */ + +/* note that the pointer should be valid allocated and not on stack */ +wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value) +{ + wmWindowManager *wm= CTX_wm_manager(C); + wmDrag *drag= MEM_callocN(sizeof(struct wmDrag), "new drag"); + + /* keep track of future multitouch drag too, add a mousepointer id or so */ + /* if multiple drags are added, they're drawn as list */ + + BLI_addtail(&wm->drags, drag); + drag->icon= icon; + drag->type= type; + if(type==WM_DRAG_PATH) + BLI_strncpy(drag->path, poin, FILE_MAX); + else + drag->poin= poin; + drag->value= value; + + return drag; +} + +void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy) +{ + drag->imb= imb; + drag->scale= scale; + drag->sx= sx; + drag->sy= sy; +} + + +static char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event) +{ + wmEventHandler *handler= handlers->first; + for(; handler; handler= handler->next) { + if(handler->dropboxes) { + wmDropBox *drop= handler->dropboxes->first; + for(; drop; drop= drop->next) { + if(drop->poll(C, drag, event)) + return drop->ot->name; + } + } + } + return NULL; +} + +/* return active operator name when mouse is in box */ +static char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event) +{ + wmWindow *win= CTX_wm_window(C); + ScrArea *sa= CTX_wm_area(C); + ARegion *ar= CTX_wm_region(C); + char *name; + + name= dropbox_active(C, &win->handlers, drag, event); + if(name) return name; + + name= dropbox_active(C, &sa->handlers, drag, event); + if(name) return name; + + name= dropbox_active(C, &ar->handlers, drag, event); + if(name) return name; + + return NULL; +} + + +static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event) +{ + wmWindow *win= CTX_wm_window(C); + + /* for multiwin drags, we only do this if mouse inside */ + if(event->x<0 || event->y<0 || event->x>win->sizex || event->y>win->sizey) + return; + + drag->opname[0]= 0; + + /* check buttons (XXX todo rna and value) */ + if( UI_but_active_drop_name(C) ) { + strcpy(drag->opname, "Paste name"); + } + else { + char *opname= wm_dropbox_active(C, drag, event); + + if(opname) { + BLI_strncpy(drag->opname, opname, FILE_MAX); + // WM_cursor_modal(win, CURSOR_COPY); + } + // else + // WM_cursor_restore(win); + /* unsure about cursor type, feels to be too much */ + } +} + +/* called in inner handler loop, region context */ +void wm_drags_check_ops(bContext *C, wmEvent *event) +{ + wmWindowManager *wm= CTX_wm_manager(C); + wmDrag *drag; + + for(drag= wm->drags.first; drag; drag= drag->next) { + wm_drop_operator_options(C, drag, event); + } +} + +/* ************** draw ***************** */ + +static void wm_drop_operator_draw(char *name, int x, int y) +{ + int width= UI_GetStringWidth(name); + + glColor4ub(0, 0, 0, 128); + + uiSetRoundBox(15); + uiRoundBox(x, y, x + width + 8, y + 15, 7); + + glColor4ub(255, 255, 255, 255); + UI_DrawString(x+4, y+4, name); +} + +static char *wm_drag_name(wmDrag *drag) +{ + switch(drag->type) { + case WM_DRAG_ID: + { + ID *id= (ID *)drag->poin; + return id->name+2; + } + case WM_DRAG_PATH: + return drag->path; + case WM_DRAG_NAME: + return (char *)drag->path; + } + return ""; +} + +static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2) +{ + if(rect->xmin > x1) + rect->xmin= x1; + 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) +{ + wmWindowManager *wm= CTX_wm_manager(C); + wmDrag *drag; + int cursorx, cursory, x, y; + + cursorx= win->eventstate->x; + cursory= win->eventstate->y; + if(rect) { + rect->xmin= rect->xmax= cursorx; + rect->ymin= rect->ymax= cursory; + } + + /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */ + glEnable(GL_BLEND); + for(drag= wm->drags.first; drag; drag= drag->next) { + + /* image or icon */ + if(drag->imb) { + x= cursorx - drag->sx/2; + y= cursory - drag->sy/2; + + if(rect) + drag_rect_minmax(rect, x, y, x+drag->sx, y+drag->sy); + else { + glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */ + glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_UNSIGNED_BYTE, drag->imb->rect, drag->scale, drag->scale); + } + } + else { + x= cursorx - 8; + y= cursory - 2; + + /* icons assumed to be 16 pixels */ + if(rect) + drag_rect_minmax(rect, x, y, x+16, y+16); + else + UI_icon_draw_aspect(x, y, drag->icon, 1.0, 0.8); + } + + /* item name */ + if(drag->imb) { + x= cursorx - drag->sx/2; + y= cursory - drag->sy/2 - 16; + } + else { + x= cursorx + 10; + y= cursory + 1; + } + + if(rect) { + int w= UI_GetStringWidth(wm_drag_name(drag)); + drag_rect_minmax(rect, x, y, x+w, y+16); + } + else { + glColor4ub(255, 255, 255, 255); + UI_DrawString(x, y, wm_drag_name(drag)); + } + + /* operator name with roundbox */ + if(drag->opname[0]) { + if(drag->imb) { + x= cursorx - drag->sx/2; + y= cursory + drag->sy/2 + 4; + } + else { + x= cursorx - 8; + y= cursory + 16; + } + + if(rect) { + int w= UI_GetStringWidth(wm_drag_name(drag)); + drag_rect_minmax(rect, x, y, x+w, y+16); + } + else + wm_drop_operator_draw(drag->opname, x, y); + + } + } + glDisable(GL_BLEND); +} |