Blender V2.61 - r43446

wm_dragdrop.c

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