doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.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
61 /* ****************************************************** */
62
63 static ListBase dropboxes= {NULL, NULL};
64
65 /* drop box maps are stored global for now */
66 /* these are part of blender's UI/space specs, and not like keymaps */
67 /* when editors become configurable, they can add own dropbox definitions */
68
69 typedef struct wmDropBoxMap {
70         struct wmDropBoxMap *next, *prev;
71         
72         ListBase dropboxes;
73         short spaceid, regionid;
74         char idname[KMAP_MAX_NAME];
75         
76 } wmDropBoxMap;
77
78 /* spaceid/regionid is zero for window drop maps */
79 ListBase *WM_dropboxmap_find(const 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         drop->opcontext= WM_OP_INVOKE_DEFAULT;
108         
109         if(drop->ot==NULL) {
110                 MEM_freeN(drop);
111                 printf("Error: dropbox with unknown operator: %s\n", idname);
112                 return NULL;
113         }
114         WM_operator_properties_alloc(&(drop->ptr), &(drop->properties), idname);
115         
116         BLI_addtail(lb, drop);
117         
118         return drop;
119 }
120
121 void wm_dropbox_free(void)
122 {
123         wmDropBoxMap *dm;
124         
125         for(dm= dropboxes.first; dm; dm= dm->next) {
126                 wmDropBox *drop;
127                 
128                 for(drop= dm->dropboxes.first; drop; drop= drop->next) {
129                         if(drop->ptr) {
130                                 WM_operator_properties_free(drop->ptr);
131                                 MEM_freeN(drop->ptr);
132                         }
133                 }
134                 BLI_freelistN(&dm->dropboxes);
135         }
136         
137         BLI_freelistN(&dropboxes);              
138 }
139
140 /* *********************************** */
141
142 /* note that the pointer should be valid allocated and not on stack */
143 wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value)
144 {
145         wmWindowManager *wm= CTX_wm_manager(C);
146         wmDrag *drag= MEM_callocN(sizeof(struct wmDrag), "new drag");
147         
148         /* keep track of future multitouch drag too, add a mousepointer id or so */
149         /* if multiple drags are added, they're drawn as list */
150         
151         BLI_addtail(&wm->drags, drag);
152         drag->icon= icon;
153         drag->type= type;
154         if(type==WM_DRAG_PATH)
155                 BLI_strncpy(drag->path, poin, FILE_MAX);
156         else
157                 drag->poin= poin;
158         drag->value= value;
159         
160         return drag;
161 }
162
163 void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
164 {
165         drag->imb= imb;
166         drag->scale= scale;
167         drag->sx= sx;
168         drag->sy= sy;
169 }
170
171
172 static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
173 {
174         wmEventHandler *handler= handlers->first;
175         for(; handler; handler= handler->next) {
176                 if(handler->dropboxes) {
177                         wmDropBox *drop= handler->dropboxes->first;
178                         for(; drop; drop= drop->next) {
179                                 if(drop->poll(C, drag, event)) 
180                                         return drop->ot->name;
181                         }
182                 }
183         }
184         return NULL;
185 }
186
187 /* return active operator name when mouse is in box */
188 static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
189 {
190         wmWindow *win= CTX_wm_window(C);
191         ScrArea *sa= CTX_wm_area(C);
192         ARegion *ar= CTX_wm_region(C);
193         const char *name;
194         
195         name= dropbox_active(C, &win->handlers, drag, event);
196         if(name) return name;
197         
198         name= dropbox_active(C, &sa->handlers, drag, event);
199         if(name) return name;
200         
201         name= dropbox_active(C, &ar->handlers, drag, event);
202         if(name) return name;
203
204         return NULL;
205 }
206
207
208 static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
209 {
210         wmWindow *win= CTX_wm_window(C);
211         
212         /* for multiwin drags, we only do this if mouse inside */
213         if(event->x<0 || event->y<0 || event->x>win->sizex || event->y>win->sizey)
214                 return;
215         
216         drag->opname[0]= 0;
217         
218         /* check buttons (XXX todo rna and value) */
219         if( UI_but_active_drop_name(C) ) {
220                 strcpy(drag->opname, "Paste name");
221         }
222         else {
223                 const char *opname= wm_dropbox_active(C, drag, event);
224                 
225                 if(opname) {
226                         BLI_strncpy(drag->opname, opname, FILE_MAX);
227                         // WM_cursor_modal(win, CURSOR_COPY);
228                 }
229                 // else
230                 //      WM_cursor_restore(win);
231                 /* unsure about cursor type, feels to be too much */
232         }
233 }
234
235 /* called in inner handler loop, region context */
236 void wm_drags_check_ops(bContext *C, wmEvent *event)
237 {
238         wmWindowManager *wm= CTX_wm_manager(C);
239         wmDrag *drag;
240         
241         for(drag= wm->drags.first; drag; drag= drag->next) {
242                 wm_drop_operator_options(C, drag, event);
243         }
244 }
245
246 /* ************** draw ***************** */
247
248 static void wm_drop_operator_draw(char *name, int x, int y)
249 {
250         int width= UI_GetStringWidth(name);
251         
252         glColor4ub(0, 0, 0, 50);
253         
254         uiSetRoundBox(15+16);   
255         uiRoundBox(x, y, x + width + 8, y + 15, 4);
256         
257         glColor4ub(255, 255, 255, 255);
258         UI_DrawString(x+4, y+4, name);
259 }
260
261 static const char *wm_drag_name(wmDrag *drag)
262 {
263         switch(drag->type) {
264                 case WM_DRAG_ID:
265                 {
266                         ID *id= (ID *)drag->poin;
267                         return id->name+2;
268                 }
269                 case WM_DRAG_PATH:
270                         return drag->path;
271                 case WM_DRAG_NAME:
272                         return (char *)drag->path;
273         }
274         return "";
275 }
276
277 static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
278 {
279         if(rect->xmin > x1)
280                 rect->xmin= x1;
281         if(rect->xmax < x2)
282                 rect->xmax= x2;
283         if(rect->ymin > y1)
284                 rect->ymin= y1;
285         if(rect->ymax < y2)
286                 rect->ymax= y2;
287 }
288
289 /* called in wm_draw.c */
290 /* if rect set, do not draw */
291 void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
292 {
293         wmWindowManager *wm= CTX_wm_manager(C);
294         wmDrag *drag;
295         int cursorx, cursory, x, y;
296         
297         cursorx= win->eventstate->x;
298         cursory= win->eventstate->y;
299         if(rect) {
300                 rect->xmin= rect->xmax= cursorx;
301                 rect->ymin= rect->ymax= cursory;
302         }
303         
304         /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
305         glEnable(GL_BLEND);
306         for(drag= wm->drags.first; drag; drag= drag->next) {
307                 
308                 /* image or icon */
309                 if(drag->imb) {
310                         x= cursorx - drag->sx/2;
311                         y= cursory - drag->sy/2;
312                         
313                         if(rect)
314                                 drag_rect_minmax(rect, x, y, x+drag->sx, y+drag->sy);
315                         else {
316                                 glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */
317                                 glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_UNSIGNED_BYTE, drag->imb->rect, drag->scale, drag->scale);
318                         }
319                 }
320                 else {
321                         x= cursorx - 8;
322                         y= cursory - 2;
323                         
324                         /* icons assumed to be 16 pixels */
325                         if(rect)
326                                 drag_rect_minmax(rect, x, y, x+16, y+16);
327                         else
328                                 UI_icon_draw_aspect(x, y, drag->icon, 1.0, 0.8);
329                 }
330                 
331                 /* item name */
332                 if(drag->imb) {
333                         x= cursorx - drag->sx/2;
334                         y= cursory - drag->sy/2 - 16;
335                 }
336                 else {
337                         x= cursorx + 10;
338                         y= cursory + 1;
339                 }
340                 
341                 if(rect) {
342                         int w=  UI_GetStringWidth(wm_drag_name(drag));
343                         drag_rect_minmax(rect, x, y, x+w, y+16);
344                 }
345                 else {
346                         glColor4ub(255, 255, 255, 255);
347                         UI_DrawString(x, y, wm_drag_name(drag));
348                 }
349                 
350                 /* operator name with roundbox */
351                 if(drag->opname[0]) {
352                         if(drag->imb) {
353                                 x= cursorx - drag->sx/2;
354                                 y= cursory + drag->sy/2 + 4;
355                         }
356                         else {
357                                 x= cursorx - 8;
358                                 y= cursory + 16;
359                         }
360                         
361                         if(rect) {
362                                 int w=  UI_GetStringWidth(wm_drag_name(drag));
363                                 drag_rect_minmax(rect, x, y, x+w, y+16);
364                         }
365                         else 
366                                 wm_drop_operator_draw(drag->opname, x, y);
367                         
368                 }
369         }
370         glDisable(GL_BLEND);
371 }