372ef107c15641a89eb75f237d88eea67c428803
[blender-staging.git] / source / blender / windowmanager / intern / wm_dragdrop.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2010 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "string.h"
30
31 #include "DNA_windowmanager_types.h"
32 #include "DNA_screen_types.h"
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37
38 #include "BIF_gl.h"
39 #include "BIF_glutil.h"
40
41 #include "BKE_blender.h"
42 #include "BKE_context.h"
43 #include "BKE_idprop.h"
44 #include "BKE_library.h"
45 #include "BKE_main.h"
46 #include "BKE_screen.h"
47 #include "BKE_global.h"
48
49 #include "IMB_imbuf_types.h"
50 #include "IMB_imbuf.h"
51
52 #include "UI_interface.h"
53 #include "UI_interface_icons.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57 #include "wm_event_system.h"
58 #include "wm.h"
59
60 #include "RNA_types.h"
61
62 /* ****************************************************** */
63
64 static ListBase dropboxes= {NULL, NULL};
65
66 /* drop box maps are stored global for now */
67 /* these are part of blender's UI/space specs, and not like keymaps */
68 /* when editors become configurable, they can add own dropbox definitions */
69
70 typedef struct wmDropBoxMap {
71         struct wmDropBoxMap *next, *prev;
72         
73         ListBase dropboxes;
74         short spaceid, regionid;
75         char idname[KMAP_MAX_NAME];
76         
77 } wmDropBoxMap;
78
79 ListBase *WM_dropboxmap_find(char *idname, int spaceid, int regionid)
80 {
81         wmDropBoxMap *dm;
82         
83         for(dm= dropboxes.first; dm; dm= dm->next)
84                 if(dm->spaceid==spaceid && dm->regionid==regionid)
85                         if(0==strncmp(idname, dm->idname, KMAP_MAX_NAME))
86                                 return &dm->dropboxes;
87         
88         dm= MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list");
89         BLI_strncpy(dm->idname, idname, KMAP_MAX_NAME);
90         dm->spaceid= spaceid;
91         dm->regionid= regionid;
92         BLI_addtail(&dropboxes, dm);
93         
94         return &dm->dropboxes;
95 }
96
97
98
99 wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(bContext *, wmDrag *, wmEvent *),
100                                                   void (*copy)(wmDrag *, wmDropBox *))
101 {
102         wmDropBox *drop= MEM_callocN(sizeof(wmDropBox), "wmDropBox");
103         
104         drop->poll= poll;
105         drop->copy= copy;
106         drop->ot= WM_operatortype_find(idname, 0);
107         
108         if(drop->ot==NULL) {
109                 MEM_freeN(drop);
110                 printf("Error: dropbox with unknown operator: %s\n", idname);
111                 return NULL;
112         }
113         WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname);
114         
115         BLI_addtail(lb, drop);
116         
117         return drop;
118 }
119
120 void wm_dropbox_free(void)
121 {
122         wmDropBoxMap *dm;
123         
124         for(dm= dropboxes.first; dm; dm= dm->next) {
125                 wmDropBox *drop;
126                 
127                 for(drop= dm->dropboxes.first; drop; drop= drop->next) {
128                         if(drop->ptr) {
129                                 WM_operator_properties_free(drop->ptr);
130                                 MEM_freeN(drop->ptr);
131                         }
132                 }
133                 BLI_freelistN(&dm->dropboxes);
134         }
135         
136         BLI_freelistN(&dropboxes);              
137 }
138
139 /* *********************************** */
140
141 /* note that the pointer should be valid allocated and not on stack */
142 wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value)
143 {
144         wmWindowManager *wm= CTX_wm_manager(C);
145         wmDrag *drag= MEM_callocN(sizeof(struct wmDrag), "new drag");
146         
147         /* keep track of future multitouch drag too, add a mousepointer id or so */
148         /* if multiple drags are added, they're drawn as list */
149         
150         BLI_addtail(&wm->drags, drag);
151         drag->icon= icon;
152         drag->type= type;
153         if(type==WM_DRAG_PATH)
154                 BLI_strncpy(drag->path, poin, FILE_MAX);
155         else
156                 drag->poin= poin;
157         drag->value= value;
158         
159         return drag;
160 }
161
162 void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
163 {
164         drag->imb= imb;
165         drag->scale= scale;
166         drag->sx= sx;
167         drag->sy= sy;
168 }
169
170
171 static char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
172 {
173         wmEventHandler *handler= handlers->first;
174         for(; handler; handler= handler->next) {
175                 if(handler->dropboxes) {
176                         wmDropBox *drop= handler->dropboxes->first;
177                         for(; drop; drop= drop->next) {
178                                 if(drop->poll(C, drag, event)) 
179                                         return drop->ot->name;
180                         }
181                 }
182         }
183         return NULL;
184 }
185
186 /* return active operator name when mouse is in box */
187 static char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
188 {
189         wmWindow *win= CTX_wm_window(C);
190         ScrArea *sa= CTX_wm_area(C);
191         ARegion *ar= CTX_wm_region(C);
192         char *name;
193         
194         name= dropbox_active(C, &win->handlers, drag, event);
195         if(name) return name;
196         
197         name= dropbox_active(C, &sa->handlers, drag, event);
198         if(name) return name;
199         
200         name= dropbox_active(C, &ar->handlers, drag, event);
201         if(name) return name;
202
203         return NULL;
204 }
205
206
207 static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
208 {
209         wmWindow *win= CTX_wm_window(C);
210         
211         /* for multiwin drags, we only do this if mouse inside */
212         if(event->x<0 || event->y<0 || event->x>win->sizex || event->y>win->sizey)
213                 return;
214         
215         drag->opname[0]= 0;
216         
217         /* check buttons (XXX todo rna and value) */
218         if( UI_but_active_drop_name(C) ) {
219                 strcpy(drag->opname, "Paste name");
220         }
221         else {
222                 char *opname= wm_dropbox_active(C, drag, event);
223                 
224                 if(opname) {
225                         BLI_strncpy(drag->opname, opname, FILE_MAX);
226                         // WM_cursor_modal(win, CURSOR_COPY);
227                 }
228                 // else
229                 //      WM_cursor_restore(win);
230                 /* unsure about cursor type, feels to be too much */
231         }
232 }
233
234 /* called in inner handler loop, region context */
235 void wm_drags_check_ops(bContext *C, wmEvent *event)
236 {
237         wmWindowManager *wm= CTX_wm_manager(C);
238         wmDrag *drag;
239         
240         for(drag= wm->drags.first; drag; drag= drag->next) {
241                 wm_drop_operator_options(C, drag, event);
242         }
243 }
244
245 /* ************** draw ***************** */
246
247 static void wm_drop_operator_draw(char *name, int x, int y)
248 {
249         int width= UI_GetStringWidth(name);
250         
251         glColor4ub(0, 0, 0, 128);
252         
253         uiSetRoundBox(15);      
254         uiRoundBox(x, y, x + width + 8, y + 15, 7);
255         
256         glColor4ub(255, 255, 255, 255);
257         UI_DrawString(x+4, y+4, name);
258 }
259
260 static char *wm_drag_name(wmDrag *drag)
261 {
262         switch(drag->type) {
263                 case WM_DRAG_ID:
264                 {
265                         ID *id= (ID *)drag->poin;
266                         return id->name+2;
267                 }
268                 case WM_DRAG_PATH:
269                         return drag->path;
270                 case WM_DRAG_NAME:
271                         return (char *)drag->path;
272         }
273         return "";
274 }
275
276 static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
277 {
278         if(rect->xmin > x1)
279                 rect->xmin= x1;
280         if(rect->xmax < x2)
281                 rect->xmax= x2;
282         if(rect->ymin > y1)
283                 rect->ymin= y1;
284         if(rect->ymax < y2)
285                 rect->ymax= y2;
286 }
287
288 /* called in wm_draw.c */
289 /* if rect set, do not draw */
290 void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
291 {
292         wmWindowManager *wm= CTX_wm_manager(C);
293         wmDrag *drag;
294         int cursorx, cursory, x, y;
295         
296         cursorx= win->eventstate->x;
297         cursory= win->eventstate->y;
298         if(rect) {
299                 rect->xmin= rect->xmax= cursorx;
300                 rect->ymin= rect->ymax= cursory;
301         }
302         
303         /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
304         glEnable(GL_BLEND);
305         for(drag= wm->drags.first; drag; drag= drag->next) {
306                 
307                 /* image or icon */
308                 if(drag->imb) {
309                         x= cursorx - drag->sx/2;
310                         y= cursory - drag->sy/2;
311                         
312                         if(rect)
313                                 drag_rect_minmax(rect, x, y, x+drag->sx, y+drag->sy);
314                         else {
315                                 glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */
316                                 glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_UNSIGNED_BYTE, drag->imb->rect, drag->scale, drag->scale);
317                         }
318                 }
319                 else {
320                         x= cursorx - 8;
321                         y= cursory - 2;
322                         
323                         /* icons assumed to be 16 pixels */
324                         if(rect)
325                                 drag_rect_minmax(rect, x, y, x+16, y+16);
326                         else
327                                 UI_icon_draw_aspect(x, y, drag->icon, 1.0, 0.8);
328                 }
329                 
330                 /* item name */
331                 if(drag->imb) {
332                         x= cursorx - drag->sx/2;
333                         y= cursory - drag->sy/2 - 16;
334                 }
335                 else {
336                         x= cursorx + 10;
337                         y= cursory + 1;
338                 }
339                 
340                 if(rect) {
341                         int w=  UI_GetStringWidth(wm_drag_name(drag));
342                         drag_rect_minmax(rect, x, y, x+w, y+16);
343                 }
344                 else {
345                         glColor4ub(255, 255, 255, 255);
346                         UI_DrawString(x, y, wm_drag_name(drag));
347                 }
348                 
349                 /* operator name with roundbox */
350                 if(drag->opname[0]) {
351                         if(drag->imb) {
352                                 x= cursorx - drag->sx/2;
353                                 y= cursory + drag->sy/2 + 4;
354                         }
355                         else {
356                                 x= cursorx - 8;
357                                 y= cursory + 16;
358                         }
359                         
360                         if(rect) {
361                                 int w=  UI_GetStringWidth(wm_drag_name(drag));
362                                 drag_rect_minmax(rect, x, y, x+w, y+16);
363                         }
364                         else 
365                                 wm_drop_operator_draw(drag->opname, x, y);
366                         
367                 }
368         }
369         glDisable(GL_BLEND);
370 }