Blender  V2.59
wm_dragdrop.c
Go to the documentation of this file.
00001 /*
00002  * $Id: wm_dragdrop.c 35179 2011-02-25 14:04:21Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2010 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <string.h>
00035 
00036 #include "DNA_windowmanager_types.h"
00037 #include "DNA_screen_types.h"
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "BLI_blenlib.h"
00042 
00043 #include "BIF_gl.h"
00044 #include "BIF_glutil.h"
00045 
00046 #include "BKE_blender.h"
00047 #include "BKE_context.h"
00048 #include "BKE_idprop.h"
00049 #include "BKE_library.h"
00050 #include "BKE_main.h"
00051 #include "BKE_screen.h"
00052 #include "BKE_global.h"
00053 
00054 #include "IMB_imbuf_types.h"
00055 #include "IMB_imbuf.h"
00056 
00057 #include "UI_interface.h"
00058 #include "UI_interface_icons.h"
00059 
00060 #include "WM_api.h"
00061 #include "WM_types.h"
00062 #include "wm_event_system.h"
00063 #include "wm.h"
00064 
00065 
00066 /* ****************************************************** */
00067 
00068 static ListBase dropboxes= {NULL, NULL};
00069 
00070 /* drop box maps are stored global for now */
00071 /* these are part of blender's UI/space specs, and not like keymaps */
00072 /* when editors become configurable, they can add own dropbox definitions */
00073 
00074 typedef struct wmDropBoxMap {
00075         struct wmDropBoxMap *next, *prev;
00076         
00077         ListBase dropboxes;
00078         short spaceid, regionid;
00079         char idname[KMAP_MAX_NAME];
00080         
00081 } wmDropBoxMap;
00082 
00083 /* spaceid/regionid is zero for window drop maps */
00084 ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
00085 {
00086         wmDropBoxMap *dm;
00087         
00088         for(dm= dropboxes.first; dm; dm= dm->next)
00089                 if(dm->spaceid==spaceid && dm->regionid==regionid)
00090                         if(0==strncmp(idname, dm->idname, KMAP_MAX_NAME))
00091                                 return &dm->dropboxes;
00092         
00093         dm= MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list");
00094         BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME);
00095         dm->spaceid= spaceid;
00096         dm->regionid= regionid;
00097         BLI_addtail(&dropboxes, dm);
00098         
00099         return &dm->dropboxes;
00100 }
00101 
00102 
00103 
00104 wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(bContext *, wmDrag *, wmEvent *),
00105                                                   void (*copy)(wmDrag *, wmDropBox *))
00106 {
00107         wmDropBox *drop= MEM_callocN(sizeof(wmDropBox), "wmDropBox");
00108         
00109         drop->poll= poll;
00110         drop->copy= copy;
00111         drop->ot= WM_operatortype_find(idname, 0);
00112         drop->opcontext= WM_OP_INVOKE_DEFAULT;
00113         
00114         if(drop->ot==NULL) {
00115                 MEM_freeN(drop);
00116                 printf("Error: dropbox with unknown operator: %s\n", idname);
00117                 return NULL;
00118         }
00119         WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname);
00120         
00121         BLI_addtail(lb, drop);
00122         
00123         return drop;
00124 }
00125 
00126 void wm_dropbox_free(void)
00127 {
00128         wmDropBoxMap *dm;
00129         
00130         for(dm= dropboxes.first; dm; dm= dm->next) {
00131                 wmDropBox *drop;
00132                 
00133                 for(drop= dm->dropboxes.first; drop; drop= drop->next) {
00134                         if(drop->ptr) {
00135                                 WM_operator_properties_free(drop->ptr);
00136                                 MEM_freeN(drop->ptr);
00137                         }
00138                 }
00139                 BLI_freelistN(&dm->dropboxes);
00140         }
00141         
00142         BLI_freelistN(&dropboxes);              
00143 }
00144 
00145 /* *********************************** */
00146 
00147 /* note that the pointer should be valid allocated and not on stack */
00148 wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value)
00149 {
00150         wmWindowManager *wm= CTX_wm_manager(C);
00151         wmDrag *drag= MEM_callocN(sizeof(struct wmDrag), "new drag");
00152         
00153         /* keep track of future multitouch drag too, add a mousepointer id or so */
00154         /* if multiple drags are added, they're drawn as list */
00155         
00156         BLI_addtail(&wm->drags, drag);
00157         drag->icon= icon;
00158         drag->type= type;
00159         if(type==WM_DRAG_PATH)
00160                 BLI_strncpy(drag->path, poin, FILE_MAX);
00161         else
00162                 drag->poin= poin;
00163         drag->value= value;
00164         
00165         return drag;
00166 }
00167 
00168 void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
00169 {
00170         drag->imb= imb;
00171         drag->scale= scale;
00172         drag->sx= sx;
00173         drag->sy= sy;
00174 }
00175 
00176 
00177 static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
00178 {
00179         wmEventHandler *handler= handlers->first;
00180         for(; handler; handler= handler->next) {
00181                 if(handler->dropboxes) {
00182                         wmDropBox *drop= handler->dropboxes->first;
00183                         for(; drop; drop= drop->next) {
00184                                 if(drop->poll(C, drag, event)) 
00185                                         return drop->ot->name;
00186                         }
00187                 }
00188         }
00189         return NULL;
00190 }
00191 
00192 /* return active operator name when mouse is in box */
00193 static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
00194 {
00195         wmWindow *win= CTX_wm_window(C);
00196         ScrArea *sa= CTX_wm_area(C);
00197         ARegion *ar= CTX_wm_region(C);
00198         const char *name;
00199         
00200         name= dropbox_active(C, &win->handlers, drag, event);
00201         if(name) return name;
00202         
00203         name= dropbox_active(C, &sa->handlers, drag, event);
00204         if(name) return name;
00205         
00206         name= dropbox_active(C, &ar->handlers, drag, event);
00207         if(name) return name;
00208 
00209         return NULL;
00210 }
00211 
00212 
00213 static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
00214 {
00215         wmWindow *win= CTX_wm_window(C);
00216         
00217         /* for multiwin drags, we only do this if mouse inside */
00218         if(event->x<0 || event->y<0 || event->x>win->sizex || event->y>win->sizey)
00219                 return;
00220         
00221         drag->opname[0]= 0;
00222         
00223         /* check buttons (XXX todo rna and value) */
00224         if( UI_but_active_drop_name(C) ) {
00225                 strcpy(drag->opname, "Paste name");
00226         }
00227         else {
00228                 const char *opname= wm_dropbox_active(C, drag, event);
00229                 
00230                 if(opname) {
00231                         BLI_strncpy(drag->opname, opname, FILE_MAX);
00232                         // WM_cursor_modal(win, CURSOR_COPY);
00233                 }
00234                 // else
00235                 //      WM_cursor_restore(win);
00236                 /* unsure about cursor type, feels to be too much */
00237         }
00238 }
00239 
00240 /* called in inner handler loop, region context */
00241 void wm_drags_check_ops(bContext *C, wmEvent *event)
00242 {
00243         wmWindowManager *wm= CTX_wm_manager(C);
00244         wmDrag *drag;
00245         
00246         for(drag= wm->drags.first; drag; drag= drag->next) {
00247                 wm_drop_operator_options(C, drag, event);
00248         }
00249 }
00250 
00251 /* ************** draw ***************** */
00252 
00253 static void wm_drop_operator_draw(char *name, int x, int y)
00254 {
00255         int width= UI_GetStringWidth(name);
00256         
00257         glColor4ub(0, 0, 0, 50);
00258         
00259         uiSetRoundBox(15+16);   
00260         uiRoundBox(x, y, x + width + 8, y + 15, 4);
00261         
00262         glColor4ub(255, 255, 255, 255);
00263         UI_DrawString(x+4, y+4, name);
00264 }
00265 
00266 static const char *wm_drag_name(wmDrag *drag)
00267 {
00268         switch(drag->type) {
00269                 case WM_DRAG_ID:
00270                 {
00271                         ID *id= (ID *)drag->poin;
00272                         return id->name+2;
00273                 }
00274                 case WM_DRAG_PATH:
00275                         return drag->path;
00276                 case WM_DRAG_NAME:
00277                         return (char *)drag->path;
00278         }
00279         return "";
00280 }
00281 
00282 static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
00283 {
00284         if(rect->xmin > x1)
00285                 rect->xmin= x1;
00286         if(rect->xmax < x2)
00287                 rect->xmax= x2;
00288         if(rect->ymin > y1)
00289                 rect->ymin= y1;
00290         if(rect->ymax < y2)
00291                 rect->ymax= y2;
00292 }
00293 
00294 /* called in wm_draw.c */
00295 /* if rect set, do not draw */
00296 void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
00297 {
00298         wmWindowManager *wm= CTX_wm_manager(C);
00299         wmDrag *drag;
00300         int cursorx, cursory, x, y;
00301         
00302         cursorx= win->eventstate->x;
00303         cursory= win->eventstate->y;
00304         if(rect) {
00305                 rect->xmin= rect->xmax= cursorx;
00306                 rect->ymin= rect->ymax= cursory;
00307         }
00308         
00309         /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
00310         glEnable(GL_BLEND);
00311         for(drag= wm->drags.first; drag; drag= drag->next) {
00312                 
00313                 /* image or icon */
00314                 if(drag->imb) {
00315                         x= cursorx - drag->sx/2;
00316                         y= cursory - drag->sy/2;
00317                         
00318                         if(rect)
00319                                 drag_rect_minmax(rect, x, y, x+drag->sx, y+drag->sy);
00320                         else {
00321                                 glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */
00322                                 glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_UNSIGNED_BYTE, drag->imb->rect, drag->scale, drag->scale);
00323                         }
00324                 }
00325                 else {
00326                         x= cursorx - 8;
00327                         y= cursory - 2;
00328                         
00329                         /* icons assumed to be 16 pixels */
00330                         if(rect)
00331                                 drag_rect_minmax(rect, x, y, x+16, y+16);
00332                         else
00333                                 UI_icon_draw_aspect(x, y, drag->icon, 1.0, 0.8);
00334                 }
00335                 
00336                 /* item name */
00337                 if(drag->imb) {
00338                         x= cursorx - drag->sx/2;
00339                         y= cursory - drag->sy/2 - 16;
00340                 }
00341                 else {
00342                         x= cursorx + 10;
00343                         y= cursory + 1;
00344                 }
00345                 
00346                 if(rect) {
00347                         int w=  UI_GetStringWidth(wm_drag_name(drag));
00348                         drag_rect_minmax(rect, x, y, x+w, y+16);
00349                 }
00350                 else {
00351                         glColor4ub(255, 255, 255, 255);
00352                         UI_DrawString(x, y, wm_drag_name(drag));
00353                 }
00354                 
00355                 /* operator name with roundbox */
00356                 if(drag->opname[0]) {
00357                         if(drag->imb) {
00358                                 x= cursorx - drag->sx/2;
00359                                 y= cursory + drag->sy/2 + 4;
00360                         }
00361                         else {
00362                                 x= cursorx - 8;
00363                                 y= cursory + 16;
00364                         }
00365                         
00366                         if(rect) {
00367                                 int w=  UI_GetStringWidth(wm_drag_name(drag));
00368                                 drag_rect_minmax(rect, x, y, x+w, y+16);
00369                         }
00370                         else 
00371                                 wm_drop_operator_draw(drag->opname, x, y);
00372                         
00373                 }
00374         }
00375         glDisable(GL_BLEND);
00376 }