5820220f7803157c55be3587edb855e0163c7453
[blender-staging.git] / source / blender / windowmanager / intern / wm_operators.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <float.h>
30 #define _USE_MATH_DEFINES
31 #include <math.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stdio.h>
35
36 #include "DNA_ID.h"
37 #include "DNA_object_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_userdef_types.h"
41 #include "DNA_windowmanager_types.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "PIL_time.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_dynstr.h" /*for WM_operator_pystring */
49
50 #include "BLO_readfile.h"
51
52 #include "BKE_blender.h"
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_idprop.h"
56 #include "BKE_library.h"
57 #include "BKE_global.h"
58 #include "BKE_main.h"
59 #include "BKE_report.h"
60 #include "BKE_scene.h"
61 #include "BKE_screen.h" /* BKE_ST_MAXNAME */
62 #include "BKE_utildefines.h"
63
64 #include "BIF_gl.h"
65 #include "BIF_glutil.h" /* for paint cursor */
66
67 #include "IMB_imbuf_types.h"
68
69 #include "ED_screen.h"
70 #include "ED_util.h"
71
72 #include "RNA_access.h"
73 #include "RNA_define.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "wm.h"
82 #include "wm_draw.h"
83 #include "wm_event_system.h"
84 #include "wm_event_types.h"
85 #include "wm_subwindow.h"
86 #include "wm_window.h"
87
88
89
90 static ListBase global_ops= {NULL, NULL};
91
92 /* ************ operator API, exported ********** */
93
94
95 wmOperatorType *WM_operatortype_find(const char *idname, int quiet)
96 {
97         wmOperatorType *ot;
98         
99         char idname_bl[OP_MAX_TYPENAME]; // XXX, needed to support python style names without the _OT_ syntax
100         WM_operator_bl_idname(idname_bl, idname);
101         
102         if (idname_bl[0]) {
103                 for(ot= global_ops.first; ot; ot= ot->next) {
104                         if(strncmp(ot->idname, idname_bl, OP_MAX_TYPENAME)==0)
105                            return ot;
106                 }
107         }
108         
109         if(!quiet)
110                 printf("search for unknown operator %s, %s\n", idname_bl, idname);
111         
112         return NULL;
113 }
114
115 wmOperatorType *WM_operatortype_exists(const char *idname)
116 {
117         wmOperatorType *ot;
118         
119         char idname_bl[OP_MAX_TYPENAME]; // XXX, needed to support python style names without the _OT_ syntax
120         WM_operator_bl_idname(idname_bl, idname);
121         
122         if(idname_bl[0]) {
123                 for(ot= global_ops.first; ot; ot= ot->next) {
124                         if(strncmp(ot->idname, idname_bl, OP_MAX_TYPENAME)==0)
125                            return ot;
126                 }
127         }
128         return NULL;
129 }
130
131 wmOperatorType *WM_operatortype_first(void)
132 {
133         return global_ops.first;
134 }
135
136 /* all ops in 1 list (for time being... needs evaluation later) */
137 void WM_operatortype_append(void (*opfunc)(wmOperatorType*))
138 {
139         wmOperatorType *ot;
140         
141         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
142         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
143         opfunc(ot);
144
145         if(ot->name==NULL) {
146                 static char dummy_name[] = "Dummy Name";
147                 fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
148                 ot->name= dummy_name;
149         }
150
151         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)"); // XXX All ops should have a description but for now allow them not to.
152         RNA_def_struct_identifier(ot->srna, ot->idname);
153         BLI_addtail(&global_ops, ot);
154 }
155
156 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata)
157 {
158         wmOperatorType *ot;
159
160         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
161         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
162         opfunc(ot, userdata);
163         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)");
164         RNA_def_struct_identifier(ot->srna, ot->idname);
165         BLI_addtail(&global_ops, ot);
166 }
167
168 /* ********************* macro operator ******************** */
169
170 typedef struct {
171         int retval;
172 } MacroData;
173
174 static void wm_macro_start(wmOperator *op)
175 {
176         if (op->customdata == NULL) {
177                 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData");
178         }
179 }
180
181 static int wm_macro_end(wmOperator *op, int retval)
182 {
183         if (retval & OPERATOR_CANCELLED) {
184                 MacroData *md = op->customdata;
185
186                 if (md->retval & OPERATOR_FINISHED) {
187                         retval |= OPERATOR_FINISHED;
188                         retval &= ~OPERATOR_CANCELLED;
189                 }
190         }
191
192         /* if modal is ending, free custom data */
193         if (retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) {
194                 if (op->customdata) {
195                         MEM_freeN(op->customdata);
196                 }
197         }
198
199         return retval;
200 }
201
202 /* macro exec only runs exec calls */
203 static int wm_macro_exec(bContext *C, wmOperator *op)
204 {
205         wmOperator *opm;
206         int retval= OPERATOR_FINISHED;
207         
208         wm_macro_start(op);
209
210         for(opm= op->macro.first; opm; opm= opm->next) {
211                 
212                 if(opm->type->exec) {
213                         retval= opm->type->exec(C, opm);
214                 
215                         if (retval & OPERATOR_FINISHED) {
216                                 MacroData *md = op->customdata;
217                                 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
218                         } else {
219                                 break; /* operator didn't finish, end macro */
220                         }
221                 }
222         }
223         
224         return wm_macro_end(op, retval);
225 }
226
227 int wm_macro_invoke_internal(bContext *C, wmOperator *op, wmEvent *event, wmOperator *opm)
228 {
229         int retval= OPERATOR_FINISHED;
230
231         /* start from operator received as argument */
232         for( ; opm; opm= opm->next) {
233                 if(opm->type->invoke)
234                         retval= opm->type->invoke(C, opm, event);
235                 else if(opm->type->exec)
236                         retval= opm->type->exec(C, opm);
237
238                 if (retval & OPERATOR_FINISHED) {
239                         MacroData *md = op->customdata;
240                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
241                 } else {
242                         break; /* operator didn't finish, end macro */
243                 }
244         }
245
246         return wm_macro_end(op, retval);
247 }
248
249 static int wm_macro_invoke(bContext *C, wmOperator *op, wmEvent *event)
250 {
251         wm_macro_start(op);
252         return wm_macro_invoke_internal(C, op, event, op->macro.first);
253 }
254
255 static int wm_macro_modal(bContext *C, wmOperator *op, wmEvent *event)
256 {
257         wmOperator *opm = op->opm;
258         int retval= OPERATOR_FINISHED;
259         
260         if(opm==NULL)
261                 printf("macro error, calling NULL modal()\n");
262         else {
263                 retval = opm->type->modal(C, opm, event);
264
265                 /* if this one is done but it's not the last operator in the macro */
266                 if ((retval & OPERATOR_FINISHED) && opm->next) {
267                         MacroData *md = op->customdata;
268
269                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
270
271                         retval = wm_macro_invoke_internal(C, op, event, opm->next);
272
273                         /* if new operator is modal and also added its own handler */
274                         if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) {
275                                 wmWindow *win = CTX_wm_window(C);
276                                 wmEventHandler *handler = NULL;
277
278                                 for (handler = win->modalhandlers.first; handler; handler = handler->next) {
279                                         /* first handler in list is the new one */
280                                         if (handler->op == op)
281                                                 break;
282                                 }
283
284                                 if (handler) {
285                                         BLI_remlink(&win->modalhandlers, handler);
286                                         wm_event_free_handler(handler);
287                                 }
288
289                                 /* if operator is blocking, grab cursor
290                                  * This may end up grabbing twice, but we don't care.
291                                  * */
292                                 if(op->opm->type->flag & OPTYPE_BLOCKING) {
293                                         int bounds[4] = {-1,-1,-1,-1};
294                                         int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
295
296                                         if(wrap) {
297                                                 ARegion *ar= CTX_wm_region(C);
298                                                 if(ar) {
299                                                         bounds[0]= ar->winrct.xmin;
300                                                         bounds[1]= ar->winrct.ymax;
301                                                         bounds[2]= ar->winrct.xmax;
302                                                         bounds[3]= ar->winrct.ymin;
303                                                 }
304                                         }
305
306                                         WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
307                                 }
308                         }
309                 }
310         }
311
312         return wm_macro_end(op, retval);
313 }
314
315 static int wm_macro_cancel(bContext *C, wmOperator *op)
316 {
317         /* call cancel on the current modal operator, if any */
318         if (op->opm && op->opm->type->cancel) {
319                 op->opm->type->cancel(C, op->opm);
320         }
321
322         return wm_macro_end(op, OPERATOR_CANCELLED);
323 }
324
325 /* Names have to be static for now */
326 wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag)
327 {
328         wmOperatorType *ot;
329         
330         if(WM_operatortype_exists(idname)) {
331                 printf("Macro error: operator %s exists\n", idname);
332                 return NULL;
333         }
334         
335         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
336         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
337         
338         ot->idname= idname;
339         ot->name= name;
340         ot->flag= OPTYPE_MACRO|flag;
341         
342         ot->exec= wm_macro_exec;
343         ot->invoke= wm_macro_invoke;
344         ot->modal= wm_macro_modal;
345         ot->cancel= wm_macro_cancel;
346         ot->poll= NULL;
347         
348         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)"); // XXX All ops should have a description but for now allow them not to.
349         RNA_def_struct_identifier(ot->srna, ot->idname);
350
351         BLI_addtail(&global_ops, ot);
352
353         return ot;
354 }
355
356 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
357 {
358         wmOperatorTypeMacro *otmacro= MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
359         
360         BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
361
362         /* do this on first use, since operatordefinitions might have been not done yet */
363         WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname);
364         
365         BLI_addtail(&ot->macro, otmacro);
366         
367         return otmacro;
368 }
369
370 static void wm_operatortype_free_macro(wmOperatorType *ot)
371 {
372         wmOperatorTypeMacro *otmacro;
373         
374         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
375                 if(otmacro->ptr) {
376                         WM_operator_properties_free(otmacro->ptr);
377                         MEM_freeN(otmacro->ptr);
378                 }
379         }
380         BLI_freelistN(&ot->macro);
381 }
382
383
384 int WM_operatortype_remove(const char *idname)
385 {
386         wmOperatorType *ot = WM_operatortype_find(idname, 0);
387
388         if (ot==NULL)
389                 return 0;
390         
391         BLI_remlink(&global_ops, ot);
392         RNA_struct_free(&BLENDER_RNA, ot->srna);
393         
394         if(ot->macro.first)
395                 wm_operatortype_free_macro(ot);
396         
397         MEM_freeN(ot);
398
399         return 1;
400 }
401
402 /* SOME_OT_op -> some.op */
403 void WM_operator_py_idname(char *to, const char *from)
404 {
405         char *sep= strstr(from, "_OT_");
406         if(sep) {
407                 int i, ofs= (sep-from);
408
409                 for(i=0; i<ofs; i++)
410                         to[i]= tolower(from[i]);
411
412                 to[ofs] = '.';
413                 BLI_strncpy(to+(ofs+1), sep+4, OP_MAX_TYPENAME);
414         }
415         else {
416                 /* should not happen but support just incase */
417                 BLI_strncpy(to, from, OP_MAX_TYPENAME);
418         }
419 }
420
421 /* some.op -> SOME_OT_op */
422 void WM_operator_bl_idname(char *to, const char *from)
423 {
424         if (from) {
425                 char *sep= strchr(from, '.');
426
427                 if(sep) {
428                         int i, ofs= (sep-from);
429
430                         for(i=0; i<ofs; i++)
431                                 to[i]= toupper(from[i]);
432
433                         BLI_strncpy(to+ofs, "_OT_", OP_MAX_TYPENAME);
434                         BLI_strncpy(to+(ofs+4), sep+1, OP_MAX_TYPENAME);
435                 }
436                 else {
437                         /* should not happen but support just incase */
438                         BLI_strncpy(to, from, OP_MAX_TYPENAME);
439                 }
440         }
441         else
442                 to[0]= 0;
443 }
444
445 /* print a string representation of the operator, with the args that it runs 
446  * so python can run it again,
447  *
448  * When calling from an existing wmOperator do.
449  * WM_operator_pystring(op->type, op->ptr);
450  */
451 char *WM_operator_pystring(bContext *C, wmOperatorType *ot, PointerRNA *opptr, int all_args)
452 {
453         const char *arg_name= NULL;
454         char idname_py[OP_MAX_TYPENAME];
455
456         PropertyRNA *prop, *iterprop;
457
458         /* for building the string */
459         DynStr *dynstr= BLI_dynstr_new();
460         char *cstring, *buf;
461         int first_iter=1, ok= 1;
462
463
464         /* only to get the orginal props for comparisons */
465         PointerRNA opptr_default;
466         PropertyRNA *prop_default;
467         char *buf_default;
468         if(all_args==0 || opptr==NULL) {
469                 WM_operator_properties_create_ptr(&opptr_default, ot);
470
471                 if(opptr==NULL)
472                         opptr = &opptr_default;
473         }
474
475
476         WM_operator_py_idname(idname_py, ot->idname);
477         BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py);
478
479         iterprop= RNA_struct_iterator_property(opptr->type);
480
481         RNA_PROP_BEGIN(opptr, propptr, iterprop) {
482                 prop= propptr.data;
483                 arg_name= RNA_property_identifier(prop);
484
485                 if (strcmp(arg_name, "rna_type")==0) continue;
486
487                 buf= RNA_property_as_string(C, opptr, prop);
488                 
489                 ok= 1;
490
491                 if(!all_args) {
492                         /* not verbose, so only add in attributes that use non-default values
493                          * slow but good for tooltips */
494                         prop_default= RNA_struct_find_property(&opptr_default, arg_name);
495
496                         if(prop_default) {
497                                 buf_default= RNA_property_as_string(C, &opptr_default, prop_default);
498
499                                 if(strcmp(buf, buf_default)==0)
500                                         ok= 0; /* values match, dont bother printing */
501
502                                 MEM_freeN(buf_default);
503                         }
504
505                 }
506                 if(ok) {
507                         BLI_dynstr_appendf(dynstr, first_iter?"%s=%s":", %s=%s", arg_name, buf);
508                         first_iter = 0;
509                 }
510
511                 MEM_freeN(buf);
512
513         }
514         RNA_PROP_END;
515
516         if(all_args==0 || opptr==&opptr_default )
517                 WM_operator_properties_free(&opptr_default);
518
519         BLI_dynstr_append(dynstr, ")");
520
521         cstring = BLI_dynstr_get_cstring(dynstr);
522         BLI_dynstr_free(dynstr);
523         return cstring;
524 }
525
526 void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
527 {
528         RNA_pointer_create(NULL, ot->srna, NULL, ptr);
529 }
530
531 void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
532 {
533         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
534
535         if(ot)
536                 WM_operator_properties_create_ptr(ptr, ot);
537         else
538                 RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
539 }
540
541 /* similar to the function above except its uses ID properties
542  * used for keymaps and macros */
543 void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
544 {
545         if(*properties==NULL) {
546                 IDPropertyTemplate val = {0};
547                 *properties= IDP_New(IDP_GROUP, val, "wmOpItemProp");
548         }
549
550         if(*ptr==NULL) {
551                 *ptr= MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
552                 WM_operator_properties_create(*ptr, opstring);
553         }
554
555         (*ptr)->data= *properties;
556
557 }
558
559
560 void WM_operator_properties_free(PointerRNA *ptr)
561 {
562         IDProperty *properties= ptr->data;
563
564         if(properties) {
565                 IDP_FreeProperty(properties);
566                 MEM_freeN(properties);
567         }
568 }
569
570 /* ************ default op callbacks, exported *********** */
571
572 /* invoke callback, uses enum property named "type" */
573 int WM_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
574 {
575         PropertyRNA *prop;
576         uiPopupMenu *pup;
577         uiLayout *layout;
578
579         prop= RNA_struct_find_property(op->ptr, "type");
580
581         if(!prop) {
582                 RNA_STRUCT_BEGIN(op->ptr, findprop) {
583                         if(RNA_property_type(findprop) == PROP_ENUM) {
584                                 prop= findprop;
585                                 break;
586                         }
587                 }
588                 RNA_STRUCT_END;
589         }
590
591         if(prop==NULL) {
592                 printf("WM_menu_invoke: %s has no \"type\" enum property\n", op->type->idname);
593         }
594         else if (RNA_property_type(prop) != PROP_ENUM) {
595                 printf("WM_menu_invoke: %s \"type\" is not an enum property\n", op->type->idname);
596         }
597         else {
598                 pup= uiPupMenuBegin(C, op->type->name, 0);
599                 layout= uiPupMenuLayout(pup);
600                 uiItemsEnumO(layout, op->type->idname, (char*)RNA_property_identifier(prop));
601                 uiPupMenuEnd(C, pup);
602         }
603
604         return OPERATOR_CANCELLED;
605 }
606
607 /* Can't be used as an invoke directly, needs message arg (can be NULL) */
608 int WM_operator_confirm_message(bContext *C, wmOperator *op, char *message)
609 {
610         uiPopupMenu *pup;
611         uiLayout *layout;
612
613         pup= uiPupMenuBegin(C, "OK?", ICON_QUESTION);
614         layout= uiPupMenuLayout(pup);
615         uiItemO(layout, message, 0, op->type->idname);
616         uiPupMenuEnd(C, pup);
617         
618         return OPERATOR_CANCELLED;
619 }
620
621
622 int WM_operator_confirm(bContext *C, wmOperator *op, wmEvent *event)
623 {
624         return WM_operator_confirm_message(C, op, NULL);
625 }
626
627 /* op->invoke, opens fileselect if path property not set, otherwise executes */
628 int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *event)
629 {
630         if (RNA_property_is_set(op->ptr, "path")) {
631                 return WM_operator_call(C, op);
632         } 
633         else {
634                 WM_event_add_fileselect(C, op);
635                 return OPERATOR_RUNNING_MODAL;
636         }
637 }
638
639 /* default properties for fileselect */
640 void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type)
641 {
642         PropertyRNA *prop;
643
644         RNA_def_string_file_path(ot->srna, "path", "", FILE_MAX, "File Path", "Path to file.");
645         RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "File Name", "Name of the file.");
646         RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Directory of the file.");
647
648         prop= RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", "");
649         RNA_def_property_flag(prop, PROP_HIDDEN);
650         prop= RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", "");
651         RNA_def_property_flag(prop, PROP_HIDDEN);
652         prop= RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", "");
653         RNA_def_property_flag(prop, PROP_HIDDEN);
654         prop= RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", "");
655         RNA_def_property_flag(prop, PROP_HIDDEN);
656         prop= RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", "");
657         RNA_def_property_flag(prop, PROP_HIDDEN);
658         prop= RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", "");
659         RNA_def_property_flag(prop, PROP_HIDDEN);
660         prop= RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", "");
661         RNA_def_property_flag(prop, PROP_HIDDEN);
662         prop= RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", "");
663         RNA_def_property_flag(prop, PROP_HIDDEN);
664
665         prop= RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, 
666                 "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file.",
667                 FILE_LOADLIB, FILE_SPECIAL);
668         RNA_def_property_flag(prop, PROP_HIDDEN);
669 }
670
671 void WM_operator_properties_gesture_border(wmOperatorType *ot, int extend)
672 {
673         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
674         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
675         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
676         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
677         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
678
679         if(extend)
680                 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first.");
681 }
682
683
684 /* op->poll */
685 int WM_operator_winactive(bContext *C)
686 {
687         if(CTX_wm_window(C)==NULL) return 0;
688         return 1;
689 }
690
691 /* op->invoke */
692 static void redo_cb(bContext *C, void *arg_op, int event)
693 {
694         wmOperator *lastop= arg_op;
695         
696         if(lastop) {
697                 ED_undo_pop_op(C, lastop);
698                 WM_operator_repeat(C, lastop);
699         }
700 }
701
702 static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
703 {
704         wmWindowManager *wm= CTX_wm_manager(C);
705         wmOperator *op= arg_op;
706         PointerRNA ptr;
707         uiBlock *block;
708         uiLayout *layout;
709         uiStyle *style= U.uistyles.first;
710         int columns= 2, width= 300;
711         
712
713         block= uiBeginBlock(C, ar, "redo_popup", UI_EMBOSS);
714         uiBlockClearFlag(block, UI_BLOCK_LOOP);
715         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
716         uiBlockSetHandleFunc(block, redo_cb, arg_op);
717
718         if(!op->properties) {
719                 IDPropertyTemplate val = {0};
720                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
721         }
722
723         // XXX - hack, only for editing docs
724         if(strcmp(op->type->idname, "WM_OT_doc_edit")==0) {
725                 columns= 1;
726                 width= 500;
727         }
728
729         RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
730         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, 20, style);
731         uiItemL(layout, op->type->name, 0);
732
733         if(op->type->ui)
734                 op->type->ui((bContext*)C, &ptr, layout);
735         else
736                 uiDefAutoButsRNA(C, layout, &ptr, columns);
737
738         uiPopupBoundsBlock(block, 4.0f, 0, 0);
739         uiEndBlock(C, block);
740
741         return block;
742 }
743
744 int WM_operator_props_popup(bContext *C, wmOperator *op, wmEvent *event)
745 {
746         int retval= OPERATOR_CANCELLED;
747         
748         if(op->type->exec)
749                 retval= op->type->exec(C, op);
750
751         if(retval != OPERATOR_CANCELLED)
752                 uiPupBlock(C, wm_block_create_redo, op);
753
754         return retval;
755 }
756
757 int WM_operator_redo_popup(bContext *C, wmOperator *op)
758 {
759         uiPupBlock(C, wm_block_create_redo, op);
760
761         return OPERATOR_CANCELLED;
762 }
763
764 /* ***************** Debug menu ************************* */
765
766 static uiBlock *wm_block_create_menu(bContext *C, ARegion *ar, void *arg_op)
767 {
768         wmOperator *op= arg_op;
769         uiBlock *block;
770         uiLayout *layout;
771         uiStyle *style= U.uistyles.first;
772         
773         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
774         uiBlockClearFlag(block, UI_BLOCK_LOOP);
775         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
776         
777         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 300, 20, style);
778         uiItemL(layout, op->type->name, 0);
779
780         if(op->type->ui)
781                 op->type->ui(C, op->ptr, layout);
782         else
783                 uiDefAutoButsRNA(C, layout, op->ptr, 2);
784         
785         uiPopupBoundsBlock(block, 4.0f, 0, 0);
786         uiEndBlock(C, block);
787         
788         return block;
789 }
790
791 static int wm_debug_menu_exec(bContext *C, wmOperator *op)
792 {
793         G.rt= RNA_int_get(op->ptr, "debugval");
794         ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
795         WM_event_add_notifier(C, NC_WINDOW, NULL);
796         
797         return OPERATOR_FINISHED;       
798 }
799
800 static int wm_debug_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
801 {
802         
803         RNA_int_set(op->ptr, "debugval", G.rt);
804         
805         /* pass on operator, so return modal */
806         uiPupBlockOperator(C, wm_block_create_menu, op, WM_OP_EXEC_DEFAULT);
807         
808         return OPERATOR_RUNNING_MODAL;
809 }
810
811 static void WM_OT_debug_menu(wmOperatorType *ot)
812 {
813         ot->name= "Debug Menu";
814         ot->idname= "WM_OT_debug_menu";
815         ot->description= "Open a popup to set the debug level.";
816         
817         ot->invoke= wm_debug_menu_invoke;
818         ot->exec= wm_debug_menu_exec;
819         ot->poll= WM_operator_winactive;
820         
821         RNA_def_int(ot->srna, "debugval", 0, -10000, 10000, "Debug Value", "", INT_MIN, INT_MAX);
822 }
823
824
825 /* ***************** Splash Screen ************************* */
826
827 static void wm_block_splash_close(bContext *C, void *arg_block, void *arg_unused)
828 {
829         uiPupBlockClose(C, arg_block);
830 }
831
832 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused)
833 {
834         uiBlock *block;
835         uiBut *but;
836         uiLayout *layout, *split, *col;
837         uiStyle *style= U.uistyles.first;
838         
839         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
840         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
841         
842         but= uiDefBut(block, BUT_IMAGE, 0, "", 0, 10, 501, 282, NULL, 0.0, 0.0, 0, 0, "");
843         uiButSetFunc(but, wm_block_splash_close, block, NULL);
844         
845         uiBlockSetEmboss(block, UI_EMBOSSP);
846         
847         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 10, 10, 480, 110, style);
848
849         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
850         
851         split = uiLayoutSplit(layout, 0);
852         col = uiLayoutColumn(split, 0);
853         uiItemL(col, "Links", 0);
854         uiItemO(col, NULL, ICON_URL, "HELP_OT_release_logs");
855         uiItemO(col, NULL, ICON_URL, "HELP_OT_manual");
856         uiItemO(col, NULL, ICON_URL, "HELP_OT_blender_website");
857         uiItemO(col, NULL, ICON_URL, "HELP_OT_user_community");
858         uiItemO(col, NULL, ICON_URL, "HELP_OT_python_api");
859         uiItemS(col);
860         
861         col = uiLayoutColumn(split, 0);
862         uiItemL(col, "Recent", 0);
863         uiItemsEnumO(col, "WM_OT_open_recentfile_splash", "file");
864         uiItemS(col);
865
866         uiCenteredBoundsBlock(block, 0.0f);
867         uiEndBlock(C, block);
868         
869         return block;
870 }
871
872 static int wm_splash_invoke(bContext *C, wmOperator *op, wmEvent *event)
873 {
874         uiPupBlock(C, wm_block_create_splash, NULL);
875         
876         return OPERATOR_FINISHED;
877 }
878
879 static void WM_OT_splash(wmOperatorType *ot)
880 {
881         ot->name= "Splash Screen";
882         ot->idname= "WM_OT_splash";
883         ot->description= "Opens a blocking popup region with release info";
884         
885         ot->invoke= wm_splash_invoke;
886         ot->poll= WM_operator_winactive;
887 }
888
889
890 /* ***************** Search menu ************************* */
891 static void operator_call_cb(struct bContext *C, void *arg1, void *arg2)
892 {
893         wmOperatorType *ot= arg2;
894         
895         if(ot)
896                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
897 }
898
899 static void operator_search_cb(const struct bContext *C, void *arg, char *str, uiSearchItems *items)
900 {
901         wmOperatorType *ot = WM_operatortype_first();
902         
903         for(; ot; ot= ot->next) {
904                 
905                 if(BLI_strcasestr(ot->name, str)) {
906                         if(WM_operator_poll((bContext*)C, ot)) {
907                                 char name[256];
908                                 int len= strlen(ot->name);
909                                 
910                                 /* display name for menu, can hold hotkey */
911                                 BLI_strncpy(name, ot->name, 256);
912                                 
913                                 /* check for hotkey */
914                                 if(len < 256-6) {
915                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
916                                                 name[len]= '|';
917                                 }
918                                 
919                                 if(0==uiSearchItemAdd(items, name, ot, 0))
920                                         break;
921                         }
922                 }
923         }
924 }
925
926 static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *arg_op)
927 {
928         static char search[256]= "";
929         wmEvent event;
930         wmWindow *win= CTX_wm_window(C);
931         uiBlock *block;
932         uiBut *but;
933         
934         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
935         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
936         
937         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, "");
938         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
939         
940         /* fake button, it holds space for search items */
941         uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxhHeight(), 180, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
942         
943         uiPopupBoundsBlock(block, 6.0f, 0, -20); /* move it downwards, mouse over button */
944         uiEndBlock(C, block);
945         
946         event= *(win->eventstate);      /* XXX huh huh? make api call */
947         event.type= EVT_BUT_OPEN;
948         event.val= KM_PRESS;
949         event.customdata= but;
950         event.customdatafree= FALSE;
951         wm_event_add(win, &event);
952         
953         return block;
954 }
955
956 static int wm_search_menu_exec(bContext *C, wmOperator *op)
957 {
958         
959         return OPERATOR_FINISHED;       
960 }
961
962 static int wm_search_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
963 {
964         
965         uiPupBlock(C, wm_block_search_menu, op);
966         
967         return OPERATOR_CANCELLED;
968 }
969
970 /* op->poll */
971 static int wm_search_menu_poll(bContext *C)
972 {
973         if(CTX_wm_window(C)==NULL) return 0;
974         if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_CONSOLE) return 0;  // XXX - so we can use the shortcut in the console
975         if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_TEXT) return 0;  // XXX - so we can use the spacebar in the text editor
976         if(CTX_data_edit_object(C) && CTX_data_edit_object(C)->type==OB_CURVE) return 0; // XXX - so we can use the spacebar for entering text
977         return 1;
978 }
979
980 static void WM_OT_search_menu(wmOperatorType *ot)
981 {
982         ot->name= "Search Menu";
983         ot->idname= "WM_OT_search_menu";
984         
985         ot->invoke= wm_search_menu_invoke;
986         ot->exec= wm_search_menu_exec;
987         ot->poll= wm_search_menu_poll;
988 }
989
990 static int wm_call_menu_invoke(bContext *C, wmOperator *op, wmEvent *event)
991 {
992         char idname[BKE_ST_MAXNAME];
993         RNA_string_get(op->ptr, "name", idname);
994
995         uiPupMenuInvoke(C, idname);
996
997         return OPERATOR_CANCELLED;
998 }
999
1000 static void WM_OT_call_menu(wmOperatorType *ot)
1001 {
1002         ot->name= "Call Menu";
1003         ot->idname= "WM_OT_call_menu";
1004
1005         ot->invoke= wm_call_menu_invoke;
1006
1007         RNA_def_string(ot->srna, "name", "", BKE_ST_MAXNAME, "Name", "Name of the new sequence strip");
1008 }
1009
1010 /* ************ window / screen operator definitions ************** */
1011
1012 static void WM_OT_window_duplicate(wmOperatorType *ot)
1013 {
1014         ot->name= "Duplicate Window";
1015         ot->idname= "WM_OT_window_duplicate";
1016         ot->description="Duplicate the current Blender window.";
1017                 
1018         ot->exec= wm_window_duplicate_op;
1019         ot->poll= WM_operator_winactive;
1020 }
1021
1022 static void WM_OT_save_homefile(wmOperatorType *ot)
1023 {
1024         ot->name= "Save User Settings";
1025         ot->idname= "WM_OT_save_homefile";
1026         ot->description="Make the current file the default .blend file.";
1027                 
1028         ot->invoke= WM_operator_confirm;
1029         ot->exec= WM_write_homefile;
1030         ot->poll= WM_operator_winactive;
1031 }
1032
1033 static void WM_OT_read_homefile(wmOperatorType *ot)
1034 {
1035         ot->name= "Reload Start-Up File";
1036         ot->idname= "WM_OT_read_homefile";
1037         ot->description="Open the default file (doesn't save the current file).";
1038         
1039         ot->invoke= WM_operator_confirm;
1040         ot->exec= WM_read_homefile;
1041         ot->poll= WM_operator_winactive;
1042         
1043         RNA_def_boolean(ot->srna, "factory", 0, "Factory Settings", "");
1044 }
1045
1046
1047 /* ********* recent file *********** */
1048
1049 static int recentfile_exec(bContext *C, wmOperator *op)
1050 {
1051         int event= RNA_enum_get(op->ptr, "file");
1052
1053         // XXX wm in context is not set correctly after WM_read_file -> crash
1054         // do it before for now, but is this correct with multiple windows?
1055
1056         if(event>0) {
1057                 if (G.sce[0] && (event==1)) {
1058                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1059                         WM_read_file(C, G.sce, op->reports);
1060                 }
1061                 else {
1062                         struct RecentFile *recent = BLI_findlink(&(G.recent_files), event-1);
1063                         if(recent) {
1064                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1065                                 WM_read_file(C, recent->filename, op->reports);
1066                         }
1067                 }
1068         }
1069         return 0;
1070 }
1071
1072 static int wm_recentfile_invoke(bContext *C, wmOperator *op, wmEvent *event)
1073 {
1074         uiPopupMenu *pup;
1075         uiLayout *layout;
1076
1077         pup= uiPupMenuBegin(C, "Open Recent", 0);
1078         layout= uiPupMenuLayout(pup);
1079         uiItemsEnumO(layout, op->type->idname, "file");
1080         uiPupMenuEnd(C, pup);
1081         
1082         return OPERATOR_CANCELLED;
1083 }
1084
1085 static EnumPropertyItem *open_recentfile_itemf(bContext *C, PointerRNA *ptr, int *free)
1086 {
1087         EnumPropertyItem tmp = {0, "", 0, "", ""};
1088         EnumPropertyItem *item= NULL;
1089         struct RecentFile *recent;
1090         int totitem= 0, i;
1091
1092         /* dynamically construct enum */
1093         for(recent = G.recent_files.first, i=0; (i<U.recent_files) && (recent); recent = recent->next, i++) {
1094                 tmp.value= i+1;
1095                 tmp.icon= ICON_FILE_BLEND;
1096                 tmp.identifier= recent->filename;
1097                 tmp.name= BLI_short_filename(recent->filename);
1098                 RNA_enum_item_add(&item, &totitem, &tmp);
1099         }
1100
1101         RNA_enum_item_end(&item, &totitem);
1102         *free= 1;
1103
1104         return item;
1105 }
1106
1107 static void WM_OT_open_recentfile(wmOperatorType *ot)
1108 {
1109         PropertyRNA *prop;
1110         static EnumPropertyItem file_items[]= {
1111                 {0, NULL, 0, NULL, NULL}};
1112
1113         ot->name= "Open Recent File";
1114         ot->idname= "WM_OT_open_recentfile";
1115         ot->description="Open recent files list.";
1116         
1117         ot->invoke= wm_recentfile_invoke;
1118         ot->exec= recentfile_exec;
1119         ot->poll= WM_operator_winactive;
1120         
1121         prop= RNA_def_enum(ot->srna, "file", file_items, 1, "File", "");
1122         RNA_def_enum_funcs(prop, open_recentfile_itemf);
1123 }
1124
1125 static EnumPropertyItem *open_recentfile_splash_itemf(bContext *C, PointerRNA *ptr, int *free)
1126 {
1127         EnumPropertyItem tmp = {0, "", 0, "", ""};
1128         EnumPropertyItem *item= NULL;
1129         struct RecentFile *recent;
1130         int totitem= 0, i;
1131         
1132         /* dynamically construct enum */
1133         for(recent = G.recent_files.first, i=0; (i<6) && (recent); recent = recent->next, i++) {
1134                 tmp.value= i+1;
1135                 tmp.icon= ICON_FILE_BLEND;
1136                 tmp.identifier= recent->filename;
1137                 tmp.name= BLI_last_slash(recent->filename);
1138                 if(tmp.name) tmp.name += 1;
1139                 else tmp.name = recent->filename;
1140                 RNA_enum_item_add(&item, &totitem, &tmp);
1141         }
1142         
1143         RNA_enum_item_end(&item, &totitem);
1144         *free= 1;
1145         
1146         return item;
1147 }
1148
1149 static void WM_OT_open_recentfile_splash(wmOperatorType *ot)
1150 {
1151         PropertyRNA *prop;
1152         static EnumPropertyItem file_items[]= {
1153                 {0, NULL, 0, NULL, NULL}};
1154         
1155         ot->name= "Open Recent File";
1156         ot->idname= "WM_OT_open_recentfile_splash";
1157         ot->description="Open recent files list.";
1158         
1159         ot->exec= recentfile_exec;
1160         ot->poll= WM_operator_winactive;
1161         
1162         prop= RNA_def_enum(ot->srna, "file", file_items, 1, "File", "");
1163         RNA_def_enum_funcs(prop, open_recentfile_splash_itemf);
1164 }
1165
1166 /* *************** open file **************** */
1167
1168 static void open_set_load_ui(wmOperator *op)
1169 {
1170         if(!RNA_property_is_set(op->ptr, "load_ui"))
1171                 RNA_boolean_set(op->ptr, "load_ui", !(U.flag & USER_FILENOUI));
1172 }
1173
1174 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event)
1175 {
1176         RNA_string_set(op->ptr, "path", G.sce);
1177         open_set_load_ui(op);
1178
1179         WM_event_add_fileselect(C, op);
1180
1181         return OPERATOR_RUNNING_MODAL;
1182 }
1183
1184 static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
1185 {
1186         char path[FILE_MAX];
1187
1188         RNA_string_get(op->ptr, "path", path);
1189         open_set_load_ui(op);
1190
1191         if(RNA_boolean_get(op->ptr, "load_ui"))
1192                 G.fileflags &= ~G_FILE_NO_UI;
1193         else
1194                 G.fileflags |= G_FILE_NO_UI;
1195         
1196         // XXX wm in context is not set correctly after WM_read_file -> crash
1197         // do it before for now, but is this correct with multiple windows?
1198         WM_event_add_notifier(C, NC_WINDOW, NULL);
1199
1200         WM_read_file(C, path, op->reports);
1201         
1202         return OPERATOR_FINISHED;
1203 }
1204
1205 static void WM_OT_open_mainfile(wmOperatorType *ot)
1206 {
1207         ot->name= "Open Blender File";
1208         ot->idname= "WM_OT_open_mainfile";
1209         ot->description="Open a Blender file.";
1210         
1211         ot->invoke= wm_open_mainfile_invoke;
1212         ot->exec= wm_open_mainfile_exec;
1213         ot->poll= WM_operator_winactive;
1214         
1215         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER);
1216
1217         RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file.");
1218 }
1219
1220 /* **************** link/append *************** */
1221
1222 static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *event)
1223 {
1224         if(RNA_property_is_set(op->ptr, "path")) {
1225                 return WM_operator_call(C, op);
1226         } 
1227         else {
1228                 /* XXX TODO solve where to get last linked library from */
1229                 RNA_string_set(op->ptr, "path", G.lib);
1230                 WM_event_add_fileselect(C, op);
1231                 return OPERATOR_RUNNING_MODAL;
1232         }
1233 }
1234
1235 static short wm_link_append_flag(wmOperator *op)
1236 {
1237         short flag= 0;
1238
1239         if(RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
1240         if(RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
1241         if(RNA_boolean_get(op->ptr, "relative_paths")) flag |= FILE_STRINGCODE;
1242         if(RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
1243
1244         return flag;
1245 }
1246
1247 static void wm_link_make_library_local(Main *main, const char *libname)
1248 {
1249         Library *lib;
1250
1251         /* and now find the latest append lib file */
1252         for(lib= main->library.first; lib; lib=lib->id.next)
1253                 if(BLI_streq(libname, lib->filename))
1254                         break;
1255         
1256         /* make local */
1257         if(lib) {
1258                 all_local(lib, 1);
1259                 /* important we unset, otherwise these object wont
1260                  * link into other scenes from this blend file */
1261                 flag_all_listbases_ids(LIB_APPEND_TAG, 0);
1262         }
1263 }
1264
1265 static int wm_link_append_exec(bContext *C, wmOperator *op)
1266 {
1267         Main *bmain= CTX_data_main(C);
1268         Scene *scene= CTX_data_scene(C);
1269         Main *mainl= 0;
1270         BlendHandle *bh;
1271         PropertyRNA *prop;
1272         char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX];
1273         int idcode, totfiles=0;
1274         short flag;
1275
1276         name[0] = '\0';
1277         RNA_string_get(op->ptr, "filename", name);
1278         RNA_string_get(op->ptr, "directory", dir);
1279
1280         /* test if we have a valid data */
1281         if(BLO_is_a_library(dir, libname, group) == 0) {
1282                 BKE_report(op->reports, RPT_ERROR, "Not a library");
1283                 return OPERATOR_CANCELLED;
1284         }
1285         else if(group[0] == 0) {
1286                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1287                 return OPERATOR_CANCELLED;
1288         }
1289         else if(BLI_streq(bmain->name, libname)) {
1290                 BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
1291                 return OPERATOR_CANCELLED;
1292         }
1293
1294         /* check if something is indicated for append/link */
1295         prop = RNA_struct_find_property(op->ptr, "files");
1296         if(prop) {
1297                 totfiles= RNA_property_collection_length(op->ptr, prop);
1298                 if(totfiles == 0) {
1299                         if(name[0] == '\0') {
1300                                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1301                                 return OPERATOR_CANCELLED;
1302                         }
1303                 }
1304         }
1305         else if(name[0] == '\0') {
1306                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1307                 return OPERATOR_CANCELLED;
1308         }
1309
1310         /* now we have or selected, or an indicated file */
1311         if(RNA_boolean_get(op->ptr, "autoselect"))
1312                 scene_deselect_all(scene);
1313
1314         bh = BLO_blendhandle_from_file(libname);
1315         idcode = BLO_idcode_from_name(group);
1316         
1317         flag = wm_link_append_flag(op);
1318
1319         /* tag everything, all untagged data can be made local */
1320         if((flag & FILE_LINK)==0)
1321                 flag_all_listbases_ids(LIB_APPEND_TAG, 1);
1322
1323         /* here appending/linking starts */
1324         mainl = BLO_library_append_begin(C, &bh, libname);
1325         if(totfiles == 0) {
1326                 BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag);
1327         }
1328         else {
1329                 RNA_BEGIN(op->ptr, itemptr, "files") {
1330                         RNA_string_get(&itemptr, "name", name);
1331                         BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag);
1332                 }
1333                 RNA_END;
1334         }
1335         BLO_library_append_end(C, mainl, &bh, idcode, flag);
1336         
1337         /* mark all library linked objects to be updated */
1338         recalc_all_library_objects(bmain);
1339
1340         /* append, rather than linking */
1341         if((flag & FILE_LINK)==0)
1342                 wm_link_make_library_local(bmain, libname);
1343
1344         /* recreate dependency graph to include new objects */
1345         DAG_scene_sort(scene);
1346         DAG_ids_flush_update(0);
1347
1348         BLO_blendhandle_close(bh);
1349
1350         /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
1351         BLI_strncpy(G.lib, dir, FILE_MAX);
1352
1353         WM_event_add_notifier(C, NC_WINDOW, NULL);
1354
1355         return OPERATOR_FINISHED;
1356 }
1357
1358 static void WM_OT_link_append(wmOperatorType *ot)
1359 {
1360         ot->name= "Link/Append from Library";
1361         ot->idname= "WM_OT_link_append";
1362         ot->description= "Link or Append from a Library .blend file";
1363         
1364         ot->invoke= wm_link_append_invoke;
1365         ot->exec= wm_link_append_exec;
1366         ot->poll= WM_operator_winactive;
1367         
1368         ot->flag |= OPTYPE_UNDO;
1369
1370         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB);
1371         
1372         RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending.");
1373         RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects.");
1374         RNA_def_boolean(ot->srna, "active_layer", 1, "Active Layer", "Put the linked objects on the active layer.");
1375         RNA_def_boolean(ot->srna, "relative_paths", 1, "Relative Paths", "Store the library path as a relative path to current .blend file.");
1376
1377         RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
1378 }       
1379
1380 /* *************** recover last session **************** */
1381
1382 static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
1383 {
1384         char filename[FILE_MAX];
1385
1386         G.fileflags |= G_FILE_RECOVER;
1387
1388         // XXX wm in context is not set correctly after WM_read_file -> crash
1389         // do it before for now, but is this correct with multiple windows?
1390         WM_event_add_notifier(C, NC_WINDOW, NULL);
1391
1392         /* load file */
1393         BLI_make_file_string("/", filename, btempdir, "quit.blend");
1394         WM_read_file(C, filename, op->reports);
1395
1396         G.fileflags &= ~G_FILE_RECOVER;
1397
1398         return OPERATOR_FINISHED;
1399 }
1400
1401 static void WM_OT_recover_last_session(wmOperatorType *ot)
1402 {
1403         ot->name= "Recover Last Session";
1404         ot->idname= "WM_OT_recover_last_session";
1405         ot->description="Open the last closed file (\"quit.blend\").";
1406         
1407         ot->exec= wm_recover_last_session_exec;
1408         ot->poll= WM_operator_winactive;
1409 }
1410
1411 /* *************** recover auto save **************** */
1412
1413 static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
1414 {
1415         char path[FILE_MAX];
1416
1417         RNA_string_get(op->ptr, "path", path);
1418
1419         G.fileflags |= G_FILE_RECOVER;
1420
1421         // XXX wm in context is not set correctly after WM_read_file -> crash
1422         // do it before for now, but is this correct with multiple windows?
1423         WM_event_add_notifier(C, NC_WINDOW, NULL);
1424
1425         /* load file */
1426         WM_read_file(C, path, op->reports);
1427
1428         G.fileflags &= ~G_FILE_RECOVER;
1429
1430         return OPERATOR_FINISHED;
1431 }
1432
1433 static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, wmEvent *event)
1434 {
1435         char filename[FILE_MAX];
1436
1437         wm_autosave_location(filename);
1438         RNA_string_set(op->ptr, "path", filename);
1439         WM_event_add_fileselect(C, op);
1440
1441         return OPERATOR_RUNNING_MODAL;
1442 }
1443
1444 static void WM_OT_recover_auto_save(wmOperatorType *ot)
1445 {
1446         ot->name= "Recover Auto Save";
1447         ot->idname= "WM_OT_recover_auto_save";
1448         ot->description="Open an automatically saved file to recover it.";
1449         
1450         ot->exec= wm_recover_auto_save_exec;
1451         ot->invoke= wm_recover_auto_save_invoke;
1452         ot->poll= WM_operator_winactive;
1453
1454         WM_operator_properties_filesel(ot, BLENDERFILE, FILE_BLENDER);
1455 }
1456
1457 /* *************** save file as **************** */
1458
1459 static void untitled(char *name)
1460 {
1461         if(G.save_over == 0 && strlen(name) < FILE_MAX-16) {
1462                 char *c= BLI_last_slash(name);
1463                 
1464                 if(c)
1465                         strcpy(&c[1], "untitled.blend");
1466                 else
1467                         strcpy(name, "untitled.blend");
1468         }
1469 }
1470
1471 static void save_set_compress(wmOperator *op)
1472 {
1473         if(!RNA_property_is_set(op->ptr, "compress")) {
1474                 if(G.save_over) /* keep flag for existing file */
1475                         RNA_boolean_set(op->ptr, "compress", G.fileflags & G_FILE_COMPRESS);
1476                 else /* use userdef for new file */
1477                         RNA_boolean_set(op->ptr, "compress", U.flag & USER_FILECOMPRESS);
1478         }
1479 }
1480
1481 static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event)
1482 {
1483         char name[FILE_MAX];
1484
1485         save_set_compress(op);
1486         
1487         BLI_strncpy(name, G.sce, FILE_MAX);
1488         untitled(name);
1489         RNA_string_set(op->ptr, "path", name);
1490         
1491         WM_event_add_fileselect(C, op);
1492
1493         return OPERATOR_RUNNING_MODAL;
1494 }
1495
1496 /* function used for WM_OT_save_mainfile too */
1497 static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
1498 {
1499         char path[FILE_MAX];
1500         int fileflags;
1501
1502         save_set_compress(op);
1503         
1504         if(RNA_property_is_set(op->ptr, "path"))
1505                 RNA_string_get(op->ptr, "path", path);
1506         else {
1507                 BLI_strncpy(path, G.sce, FILE_MAX);
1508                 untitled(path);
1509         }
1510
1511         fileflags= G.fileflags;
1512
1513         /* set compression flag */
1514         if(RNA_boolean_get(op->ptr, "compress"))
1515                 fileflags |= G_FILE_COMPRESS;
1516         else
1517                 fileflags &= ~G_FILE_COMPRESS;
1518
1519         WM_write_file(C, path, fileflags, op->reports);
1520         
1521         WM_event_add_notifier(C, NC_WM|ND_FILESAVE, NULL);
1522
1523         return 0;
1524 }
1525
1526 static void WM_OT_save_as_mainfile(wmOperatorType *ot)
1527 {
1528         ot->name= "Save As Blender File";
1529         ot->idname= "WM_OT_save_as_mainfile";
1530         ot->description="Save the current file in the desired location.";
1531         
1532         ot->invoke= wm_save_as_mainfile_invoke;
1533         ot->exec= wm_save_as_mainfile_exec;
1534         ot->poll= WM_operator_winactive;
1535         
1536         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER);
1537         RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file.");
1538 }
1539
1540 /* *************** save file directly ******** */
1541
1542 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *event)
1543 {
1544         char name[FILE_MAX];
1545
1546         save_set_compress(op);
1547         
1548         BLI_strncpy(name, G.sce, FILE_MAX);
1549         untitled(name);
1550         RNA_string_set(op->ptr, "path", name);
1551         
1552         if (G.save_over)
1553                 uiPupMenuSaveOver(C, op, name);
1554         else
1555                 WM_event_add_fileselect(C, op);
1556         
1557         return OPERATOR_RUNNING_MODAL;
1558 }
1559
1560 static void WM_OT_save_mainfile(wmOperatorType *ot)
1561 {
1562         ot->name= "Save Blender File";
1563         ot->idname= "WM_OT_save_mainfile";
1564         ot->description="Save the current Blender file.";
1565         
1566         ot->invoke= wm_save_mainfile_invoke;
1567         ot->exec= wm_save_as_mainfile_exec;
1568         ot->poll= WM_operator_winactive;
1569         
1570         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER);
1571         RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file.");
1572 }
1573
1574
1575 /* XXX: move these collada operators to a more appropriate place */
1576 #ifdef WITH_COLLADA
1577
1578 #include "../../collada/collada.h"
1579
1580 static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *event)
1581 {
1582         //char name[FILE_MAX];
1583         //BLI_strncpy(name, G.sce, FILE_MAX);
1584         //untitled(name);
1585
1586         /* RNA_string_set(op->ptr, "path", "/tmp/test.dae"); */
1587         
1588         WM_event_add_fileselect(C, op);
1589
1590         return OPERATOR_RUNNING_MODAL;
1591 }
1592
1593 /* function used for WM_OT_save_mainfile too */
1594 static int wm_collada_export_exec(bContext *C, wmOperator *op)
1595 {
1596         char filename[FILE_MAX];
1597         
1598         if(RNA_property_is_set(op->ptr, "path"))
1599                 RNA_string_get(op->ptr, "path", filename);
1600         else {
1601                 BLI_strncpy(filename, G.sce, FILE_MAX);
1602                 untitled(filename);
1603         }
1604         
1605         //WM_write_file(C, filename, op->reports);
1606         collada_export(CTX_data_scene(C), filename);
1607         
1608         /* WM_event_add_notifier(C, NC_WM|ND_FILESAVE, NULL); */
1609
1610         return OPERATOR_FINISHED;
1611 }
1612
1613 static void WM_OT_collada_export(wmOperatorType *ot)
1614 {
1615         ot->name= "Export COLLADA";
1616         ot->idname= "WM_OT_collada_export";
1617         
1618         ot->invoke= wm_collada_export_invoke;
1619         ot->exec= wm_collada_export_exec;
1620         ot->poll= WM_operator_winactive;
1621         
1622         ot->flag= 0;
1623         
1624         RNA_def_property(ot->srna, "path", PROP_STRING, PROP_FILEPATH);
1625 }
1626
1627 static int wm_collada_import_invoke(bContext *C, wmOperator *op, wmEvent *event)
1628 {
1629         /* RNA_string_set(op->ptr, "path", "/tmp/test.dae"); */
1630         
1631         WM_event_add_fileselect(C, op);
1632
1633         return OPERATOR_RUNNING_MODAL;
1634 }
1635
1636 /* function used for WM_OT_save_mainfile too */
1637 static int wm_collada_import_exec(bContext *C, wmOperator *op)
1638 {
1639         char filename[FILE_MAX];
1640         
1641         if(RNA_property_is_set(op->ptr, "path"))
1642                 RNA_string_get(op->ptr, "path", filename);
1643         else {
1644                 BLI_strncpy(filename, G.sce, FILE_MAX);
1645                 untitled(filename);
1646         }
1647         
1648         //WM_write_file(C, filename, op->reports);
1649         collada_import(C, filename);
1650         
1651         /* WM_event_add_notifier(C, NC_WM|ND_FILESAVE, NULL); */
1652
1653         return OPERATOR_FINISHED;
1654 }
1655
1656 static void WM_OT_collada_import(wmOperatorType *ot)
1657 {
1658         ot->name= "Import COLLADA";
1659         ot->idname= "WM_OT_collada_import";
1660         
1661         ot->invoke= wm_collada_import_invoke;
1662         ot->exec= wm_collada_import_exec;
1663         ot->poll= WM_operator_winactive;
1664         
1665         ot->flag= 0;
1666         
1667         RNA_def_property(ot->srna, "path", PROP_STRING, PROP_FILEPATH);
1668 }
1669
1670 #endif
1671
1672
1673
1674 /* *********************** */
1675
1676 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
1677 {
1678         ot->name= "Toggle Fullscreen";
1679         ot->idname= "WM_OT_window_fullscreen_toggle";
1680         ot->description="Toggle the current window fullscreen.";
1681
1682         ot->exec= wm_window_fullscreen_toggle_op;
1683         ot->poll= WM_operator_winactive;
1684 }
1685
1686 static int wm_exit_blender_op(bContext *C, wmOperator *op)
1687 {
1688         WM_operator_free(op);
1689         
1690         WM_exit(C);     
1691         
1692         return OPERATOR_FINISHED;
1693 }
1694
1695 static void WM_OT_exit_blender(wmOperatorType *ot)
1696 {
1697         ot->name= "Exit Blender";
1698         ot->idname= "WM_OT_exit_blender";
1699         ot->description= "Quit Blender.";
1700
1701         ot->invoke= WM_operator_confirm;
1702         ot->exec= wm_exit_blender_op;
1703         ot->poll= WM_operator_winactive;
1704 }
1705
1706 /* ************ default paint cursors, draw always around cursor *********** */
1707 /*
1708  - returns handler to free 
1709  - poll(bContext): returns 1 if draw should happen
1710  - draw(bContext): drawing callback for paint cursor
1711 */
1712
1713 void *WM_paint_cursor_activate(wmWindowManager *wm, int (*poll)(bContext *C),
1714                                wmPaintCursorDraw draw, void *customdata)
1715 {
1716         wmPaintCursor *pc= MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
1717         
1718         BLI_addtail(&wm->paintcursors, pc);
1719         
1720         pc->customdata = customdata;
1721         pc->poll= poll;
1722         pc->draw= draw;
1723         
1724         return pc;
1725 }
1726
1727 void WM_paint_cursor_end(wmWindowManager *wm, void *handle)
1728 {
1729         wmPaintCursor *pc;
1730         
1731         for(pc= wm->paintcursors.first; pc; pc= pc->next) {
1732                 if(pc == (wmPaintCursor *)handle) {
1733                         BLI_remlink(&wm->paintcursors, pc);
1734                         MEM_freeN(pc);
1735                         return;
1736                 }
1737         }
1738 }
1739
1740 /* ************ window gesture operator-callback definitions ************** */
1741 /*
1742  * These are default callbacks for use in operators requiring gesture input
1743  */
1744
1745 /* **************** Border gesture *************** */
1746
1747 /* Border gesture has two types:
1748    1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border 
1749    2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends
1750
1751    It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type)
1752 */
1753
1754 static int border_apply(bContext *C, wmOperator *op, int gesture_mode)
1755 {
1756         wmGesture *gesture= op->customdata;
1757         rcti *rect= gesture->customdata;
1758         
1759         if(rect->xmin > rect->xmax)
1760                 SWAP(int, rect->xmin, rect->xmax);
1761         if(rect->ymin > rect->ymax)
1762                 SWAP(int, rect->ymin, rect->ymax);
1763         
1764         if(rect->xmin==rect->xmax || rect->ymin==rect->ymax)
1765                 return 0;
1766                 
1767         /* operator arguments and storage. */
1768         RNA_int_set(op->ptr, "xmin", rect->xmin);
1769         RNA_int_set(op->ptr, "ymin", rect->ymin);
1770         RNA_int_set(op->ptr, "xmax", rect->xmax);
1771         RNA_int_set(op->ptr, "ymax", rect->ymax);
1772         
1773         /* XXX weak; border should be configured for this without reading event types */
1774         if( RNA_struct_find_property(op->ptr, "gesture_mode") )
1775                 RNA_int_set(op->ptr, "gesture_mode", gesture_mode);
1776
1777         op->type->exec(C, op);
1778         
1779         return 1;
1780 }
1781
1782 static void wm_gesture_end(bContext *C, wmOperator *op)
1783 {
1784         wmGesture *gesture= op->customdata;
1785         
1786         WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
1787         op->customdata= NULL;
1788
1789         ED_area_tag_redraw(CTX_wm_area(C));
1790         
1791         if( RNA_struct_find_property(op->ptr, "cursor") )
1792                 WM_cursor_restore(CTX_wm_window(C));
1793 }
1794
1795 int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1796 {
1797         if(ISTWEAK(event->type))
1798                 op->customdata= WM_gesture_new(C, event, WM_GESTURE_RECT);
1799         else
1800                 op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT);
1801
1802         /* add modal handler */
1803         WM_event_add_modal_handler(C, op);
1804         
1805         wm_gesture_tag_redraw(C);
1806
1807         return OPERATOR_RUNNING_MODAL;
1808 }
1809
1810 int WM_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
1811 {
1812         wmGesture *gesture= op->customdata;
1813         rcti *rect= gesture->customdata;
1814         int sx, sy;
1815         
1816         if(event->type== MOUSEMOVE) {
1817                 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
1818
1819                 if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
1820                         rect->xmin= rect->xmax= event->x - sx;
1821                         rect->ymin= rect->ymax= event->y - sy;
1822                 }
1823                 else {
1824                         rect->xmax= event->x - sx;
1825                         rect->ymax= event->y - sy;
1826                 }
1827
1828                 wm_gesture_tag_redraw(C);
1829         }
1830         else if (event->type==EVT_MODAL_MAP) {
1831                 switch (event->val) {
1832                 case GESTURE_MODAL_BORDER_BEGIN:
1833                         if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
1834                                 gesture->mode= 1;
1835                                 wm_gesture_tag_redraw(C);
1836                         }
1837                         break;
1838                 case GESTURE_MODAL_SELECT:
1839                 case GESTURE_MODAL_DESELECT:
1840                         if(border_apply(C, op, event->val)) {
1841                                 wm_gesture_end(C, op);
1842                                 return OPERATOR_FINISHED;
1843                         }
1844                         wm_gesture_end(C, op);
1845                         return OPERATOR_CANCELLED;
1846                         break;
1847
1848                 case GESTURE_MODAL_CANCEL:
1849                         wm_gesture_end(C, op);
1850                         return OPERATOR_CANCELLED;
1851                 }
1852
1853         }
1854 //      // Allow view navigation???
1855 //      else {
1856 //              return OPERATOR_PASS_THROUGH;
1857 //      }
1858
1859         return OPERATOR_RUNNING_MODAL;
1860 }
1861
1862 /* **************** circle gesture *************** */
1863 /* works now only for selection or modal paint stuff, calls exec while hold mouse, exit on release */
1864
1865 #ifdef GESTURE_MEMORY
1866 int circle_select_size= 25; // XXX - need some operator memory thing\!
1867 #endif
1868
1869 int WM_gesture_circle_invoke(bContext *C, wmOperator *op, wmEvent *event)
1870 {
1871         op->customdata= WM_gesture_new(C, event, WM_GESTURE_CIRCLE);
1872         
1873         /* add modal handler */
1874         WM_event_add_modal_handler(C, op);
1875         
1876         wm_gesture_tag_redraw(C);
1877         
1878         return OPERATOR_RUNNING_MODAL;
1879 }
1880
1881 static void gesture_circle_apply(bContext *C, wmOperator *op)
1882 {
1883         wmGesture *gesture= op->customdata;
1884         rcti *rect= gesture->customdata;
1885         
1886     if(RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_NOP)
1887         return;
1888
1889         /* operator arguments and storage. */
1890         RNA_int_set(op->ptr, "x", rect->xmin);
1891         RNA_int_set(op->ptr, "y", rect->ymin);
1892         RNA_int_set(op->ptr, "radius", rect->xmax);
1893         
1894         if(op->type->exec)
1895                 op->type->exec(C, op);
1896
1897 #ifdef GESTURE_MEMORY
1898         circle_select_size= rect->xmax;
1899 #endif
1900 }
1901
1902 int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event)
1903 {
1904         wmGesture *gesture= op->customdata;
1905         rcti *rect= gesture->customdata;
1906         int sx, sy;
1907
1908         if(event->type== MOUSEMOVE) {
1909                 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
1910
1911                 rect->xmin= event->x - sx;
1912                 rect->ymin= event->y - sy;
1913
1914                 wm_gesture_tag_redraw(C);
1915
1916                 if(gesture->mode)
1917                         gesture_circle_apply(C, op);
1918         }
1919         else if (event->type==EVT_MODAL_MAP) {
1920                 switch (event->val) {
1921                 case GESTURE_MODAL_CIRCLE_ADD:
1922                         rect->xmax += 2 + rect->xmax/10;
1923                         wm_gesture_tag_redraw(C);
1924                         break;
1925                 case GESTURE_MODAL_CIRCLE_SUB:
1926                         rect->xmax -= 2 + rect->xmax/10;
1927                         if(rect->xmax < 1) rect->xmax= 1;
1928                         wm_gesture_tag_redraw(C);
1929                         break;
1930                 case GESTURE_MODAL_SELECT:
1931                 case GESTURE_MODAL_DESELECT:
1932                 case GESTURE_MODAL_NOP:
1933                         if(RNA_struct_find_property(op->ptr, "gesture_mode"))
1934                                 RNA_int_set(op->ptr, "gesture_mode", event->val);
1935
1936                         if(event->val != GESTURE_MODAL_NOP) {
1937                                 /* apply first click */
1938                                 gesture_circle_apply(C, op);
1939                                 gesture->mode= 1;
1940                         }
1941                         break;
1942
1943                 case GESTURE_MODAL_CANCEL:
1944                 case GESTURE_MODAL_CONFIRM:
1945                         wm_gesture_end(C, op);
1946                         return OPERATOR_CANCELLED;
1947                 }
1948         }
1949 //      // Allow view navigation???
1950 //      else {
1951 //              return OPERATOR_PASS_THROUGH;
1952 //      }
1953
1954         return OPERATOR_RUNNING_MODAL;
1955 }
1956
1957 #if 0
1958 /* template to copy from */
1959 void WM_OT_circle_gesture(wmOperatorType *ot)
1960 {
1961         ot->name= "Circle Gesture";
1962         ot->idname= "WM_OT_circle_gesture";
1963         ot->description="Enter rotate mode with a circular gesture.";
1964         
1965         ot->invoke= WM_gesture_circle_invoke;
1966         ot->modal= WM_gesture_circle_modal;
1967         
1968         ot->poll= WM_operator_winactive;
1969         
1970         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
1971         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
1972         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
1973
1974 }
1975 #endif
1976
1977 /* **************** Tweak gesture *************** */
1978
1979 static void tweak_gesture_modal(bContext *C, wmEvent *event)
1980 {
1981         wmWindow *window= CTX_wm_window(C);
1982         wmGesture *gesture= window->tweak;
1983         rcti *rect= gesture->customdata;
1984         int sx, sy, val;
1985         
1986         switch(event->type) {
1987                 case MOUSEMOVE:
1988                         
1989                         wm_subwindow_getorigin(window, gesture->swinid, &sx, &sy);
1990                         
1991                         rect->xmax= event->x - sx;
1992                         rect->ymax= event->y - sy;
1993                         
1994                         if((val= wm_gesture_evaluate(C, gesture))) {
1995                                 wmEvent event;
1996
1997                                 event= *(window->eventstate);
1998                                 if(gesture->event_type==LEFTMOUSE)
1999                                         event.type= EVT_TWEAK_L;
2000                                 else if(gesture->event_type==RIGHTMOUSE)
2001                                         event.type= EVT_TWEAK_R;
2002                                 else
2003                                         event.type= EVT_TWEAK_M;
2004                                 event.val= val;
2005                                 /* mouse coords! */
2006                                 wm_event_add(window, &event);
2007                                 
2008                                 WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
2009                                 window->tweak= NULL;
2010                         }
2011                         
2012                         break;
2013                         
2014                 case LEFTMOUSE:
2015                 case RIGHTMOUSE:
2016                 case MIDDLEMOUSE:
2017                         if(gesture->event_type==event->type) {
2018                                 WM_gesture_end(C, gesture);
2019                                 window->tweak= NULL;
2020
2021                                 /* when tweak fails we should give the other keymap entries a chance */
2022                                 event->val= KM_RELEASE;
2023                         }
2024                         break;
2025                 default:
2026                         if(!ISTIMER(event->type)) {
2027                                 WM_gesture_end(C, gesture);
2028                                 window->tweak= NULL;
2029                         }
2030                         break;
2031         }
2032 }
2033
2034 /* standard tweak, called after window handlers passed on event */
2035 void wm_tweakevent_test(bContext *C, wmEvent *event, int action)
2036 {
2037         wmWindow *win= CTX_wm_window(C);
2038         
2039         if(win->tweak==NULL) {
2040                 if(CTX_wm_region(C)) {
2041                         if(event->val==KM_PRESS) { // pressed
2042                                 if( ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) )
2043                                         win->tweak= WM_gesture_new(C, event, WM_GESTURE_TWEAK);
2044                         }
2045                 }
2046         }
2047         else {
2048                 if(action & WM_HANDLER_BREAK) {
2049                         WM_gesture_end(C, win->tweak);
2050                         win->tweak= NULL;
2051                 }
2052                 else
2053                         tweak_gesture_modal(C, event);
2054         }
2055 }
2056
2057 /* *********************** lasso gesture ****************** */
2058
2059 int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, wmEvent *event)
2060 {
2061         op->customdata= WM_gesture_new(C, event, WM_GESTURE_LASSO);
2062         
2063         /* add modal handler */
2064         WM_event_add_modal_handler(C, op);
2065         
2066         wm_gesture_tag_redraw(C);
2067         
2068         if( RNA_struct_find_property(op->ptr, "cursor") )
2069                 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor"));
2070         
2071         return OPERATOR_RUNNING_MODAL;
2072 }
2073
2074 int WM_gesture_lines_invoke(bContext *C, wmOperator *op, wmEvent *event)
2075 {
2076         op->customdata= WM_gesture_new(C, event, WM_GESTURE_LINES);
2077         
2078         /* add modal handler */
2079         WM_event_add_modal_handler(C, op);
2080         
2081         wm_gesture_tag_redraw(C);
2082         
2083         if( RNA_struct_find_property(op->ptr, "cursor") )
2084                 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor"));
2085         
2086         return OPERATOR_RUNNING_MODAL;
2087 }
2088
2089
2090 static void gesture_lasso_apply(bContext *C, wmOperator *op, int event_type)
2091 {
2092         wmGesture *gesture= op->customdata;
2093         PointerRNA itemptr;
2094         float loc[2];
2095         int i;
2096         short *lasso= gesture->customdata;
2097         
2098         /* operator storage as path. */
2099
2100         for(i=0; i<gesture->points; i++, lasso+=2) {
2101                 loc[0]= lasso[0];
2102                 loc[1]= lasso[1];
2103                 RNA_collection_add(op->ptr, "path", &itemptr);
2104                 RNA_float_set_array(&itemptr, "loc", loc);
2105         }
2106         
2107         wm_gesture_end(C, op);
2108                 
2109         if(op->type->exec)
2110                 op->type->exec(C, op);
2111         
2112 }
2113
2114 int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event)
2115 {
2116         wmGesture *gesture= op->customdata;
2117         int sx, sy;
2118         
2119         switch(event->type) {
2120                 case MOUSEMOVE:
2121                         
2122                         wm_gesture_tag_redraw(C);
2123                         
2124                         wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
2125                         if(gesture->points < WM_LASSO_MAX_POINTS) {
2126                                 short *lasso= gesture->customdata;
2127                                 lasso += 2 * gesture->points;
2128                                 lasso[0] = event->x - sx;
2129                                 lasso[1] = event->y - sy;
2130                                 gesture->points++;
2131                         }
2132                         else {
2133                                 gesture_lasso_apply(C, op, event->type);
2134                                 return OPERATOR_FINISHED;
2135                         }
2136                         break;
2137                         
2138                 case LEFTMOUSE:
2139                 case MIDDLEMOUSE:
2140                 case RIGHTMOUSE:
2141                         if(event->val==KM_RELEASE) {    /* key release */
2142                                 gesture_lasso_apply(C, op, event->type);
2143                                 return OPERATOR_FINISHED;
2144                         }
2145                         break;
2146                 case ESCKEY:
2147                         wm_gesture_end(C, op);
2148                         return OPERATOR_CANCELLED;
2149         }
2150         return OPERATOR_RUNNING_MODAL;
2151 }
2152
2153 int WM_gesture_lines_modal(bContext *C, wmOperator *op, wmEvent *event)
2154 {
2155         return WM_gesture_lasso_modal(C, op, event);
2156 }
2157
2158 #if 0
2159 /* template to copy from */
2160
2161 static int gesture_lasso_exec(bContext *C, wmOperator *op)
2162 {
2163         RNA_BEGIN(op->ptr, itemptr, "path") {
2164                 float loc[2];
2165                 
2166                 RNA_float_get_array(&itemptr, "loc", loc);
2167                 printf("Location: %f %f\n", loc[0], loc[1]);
2168         }
2169         RNA_END;
2170         
2171         return OPERATOR_FINISHED;
2172 }
2173
2174 void WM_OT_lasso_gesture(wmOperatorType *ot)
2175 {
2176         PropertyRNA *prop;
2177         
2178         ot->name= "Lasso Gesture";
2179         ot->idname= "WM_OT_lasso_gesture";
2180         ot->description="Select objects within the lasso as you move the pointer.";
2181         
2182         ot->invoke= WM_gesture_lasso_invoke;
2183         ot->modal= WM_gesture_lasso_modal;
2184         ot->exec= gesture_lasso_exec;
2185         
2186         ot->poll= WM_operator_winactive;
2187         
2188         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
2189         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
2190 }
2191 #endif
2192
2193 /* *********************** radial control ****************** */
2194
2195 const int WM_RADIAL_CONTROL_DISPLAY_SIZE = 200;
2196
2197 typedef struct wmRadialControl {
2198         int mode;
2199         float initial_value, value, max_value;
2200         int initial_mouse[2];
2201         void *cursor;
2202         GLuint tex;
2203 } wmRadialControl;
2204
2205 static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
2206 {
2207         wmRadialControl *rc = (wmRadialControl*)customdata;
2208         ARegion *ar = CTX_wm_region(C);
2209         float r1=0.0f, r2=0.0f, r3=0.0f, angle=0.0f;
2210
2211         /* Keep cursor in the original place */
2212         x = rc->initial_mouse[0] - ar->winrct.xmin;
2213         y = rc->initial_mouse[1] - ar->winrct.ymin;
2214
2215         glPushMatrix();
2216         
2217         glTranslatef((float)x, (float)y, 0.0f);
2218
2219         if(rc->mode == WM_RADIALCONTROL_SIZE) {
2220                 r1= rc->value;
2221                 r2= rc->initial_value;
2222                 r3= r1;
2223         } else if(rc->mode == WM_RADIALCONTROL_STRENGTH) {
2224                 r1= (1 - rc->value) * WM_RADIAL_CONTROL_DISPLAY_SIZE;
2225                 r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
2226                 r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
2227         } else if(rc->mode == WM_RADIALCONTROL_ANGLE) {
2228                 r1= r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
2229                 r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
2230                 angle = rc->value;
2231         }
2232
2233         glColor4ub(255, 255, 255, 128);
2234         glEnable( GL_LINE_SMOOTH );
2235         glEnable(GL_BLEND);
2236
2237         if(rc->mode == WM_RADIALCONTROL_ANGLE)
2238                 fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
2239
2240         if(rc->tex) {
2241                 const float str = rc->mode == WM_RADIALCONTROL_STRENGTH ? (rc->value + 0.5) : 1;
2242
2243                 if(rc->mode == WM_RADIALCONTROL_ANGLE) {
2244                         glRotatef(angle, 0, 0, 1);
2245                         fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
2246                 }
2247
2248                 glBindTexture(GL_TEXTURE_2D, rc->tex);
2249
2250                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2251                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2252
2253                 glEnable(GL_TEXTURE_2D);
2254                 glBegin(GL_QUADS);
2255                 glColor4f(0,0,0, str);
2256                 glTexCoord2f(0,0);
2257                 glVertex2f(-r3, -r3);
2258                 glTexCoord2f(1,0);
2259                 glVertex2f(r3, -r3);
2260                 glTexCoord2f(1,1);
2261                 glVertex2f(r3, r3);
2262                 glTexCoord2f(0,1);
2263                 glVertex2f(-r3, r3);
2264                 glEnd();
2265                 glDisable(GL_TEXTURE_2D);
2266         }
2267
2268         glColor4ub(255, 255, 255, 128); 
2269         glutil_draw_lined_arc(0.0, M_PI*2.0, r1, 40);
2270         glutil_draw_lined_arc(0.0, M_PI*2.0, r2, 40);
2271         glDisable(GL_BLEND);
2272         glDisable( GL_LINE_SMOOTH );
2273         
2274         glPopMatrix();
2275 }
2276
2277 int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2278 {
2279         wmRadialControl *rc = (wmRadialControl*)op->customdata;
2280         int mode, initial_mouse[2], delta[2];
2281         float dist;
2282         double new_value = RNA_float_get(op->ptr, "new_value");
2283         int ret = OPERATOR_RUNNING_MODAL;
2284
2285         mode = RNA_int_get(op->ptr, "mode");
2286         RNA_int_get_array(op->ptr, "initial_mouse", initial_mouse);
2287
2288         switch(event->type) {
2289         case MOUSEMOVE:
2290                 delta[0]= initial_mouse[0] - event->x;
2291                 delta[1]= initial_mouse[1] - event->y;
2292                 dist= sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
2293
2294                 if(mode == WM_RADIALCONTROL_SIZE)
2295                         new_value = dist;
2296                 else if(mode == WM_RADIALCONTROL_STRENGTH) {
2297                         new_value = 1 - dist / WM_RADIAL_CONTROL_DISPLAY_SIZE;
2298                 } else if(mode == WM_RADIALCONTROL_ANGLE)
2299                         new_value = ((int)(atan2(delta[1], delta[0]) * (180.0 / M_PI)) + 180);
2300                 
2301                 if(event->ctrl) {
2302                         if(mode == WM_RADIALCONTROL_STRENGTH)
2303                                 new_value = ((int)(new_value * 100) / 10*10) / 100.0f;
2304                         else
2305                                 new_value = ((int)new_value + 5) / 10*10;
2306                 }
2307                 
2308                 break;
2309         case ESCKEY:
2310         case RIGHTMOUSE:
2311                 ret = OPERATOR_CANCELLED;
2312                 break;
2313         case LEFTMOUSE:
2314         case PADENTER:
2315                 op->type->exec(C, op);
2316                 ret = OPERATOR_FINISHED;
2317                 break;
2318         }
2319
2320         /* Clamp */
2321         if(new_value > rc->max_value)
2322                 new_value = rc->max_value;
2323         else if(new_value < 0)
2324                 new_value = 0;
2325
2326         /* Update paint data */
2327         rc->value = new_value;
2328
2329         RNA_float_set(op->ptr, "new_value", new_value);
2330
2331         if(ret != OPERATOR_RUNNING_MODAL) {
2332                 WM_paint_cursor_end(CTX_wm_manager(C), rc->cursor);
2333                 MEM_freeN(rc);
2334         }
2335         
2336         ED_region_tag_redraw(CTX_wm_region(C));
2337
2338         return ret;
2339 }
2340
2341 /* Expects the operator customdata to be an ImBuf (or NULL) */
2342 int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2343 {
2344         wmRadialControl *rc = MEM_callocN(sizeof(wmRadialControl), "radial control");
2345         int mode = RNA_int_get(op->ptr, "mode");
2346         float initial_value = RNA_float_get(op->ptr, "initial_value");
2347         int mouse[2] = {event->x, event->y};
2348
2349         if(mode == WM_RADIALCONTROL_SIZE) {
2350                 rc->max_value = 200;
2351                 mouse[0]-= initial_value;
2352         }
2353         else if(mode == WM_RADIALCONTROL_STRENGTH) {
2354                 rc->max_value = 1;
2355                 mouse[0]-= WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - initial_value);
2356         }
2357         else if(mode == WM_RADIALCONTROL_ANGLE) {
2358                 rc->max_value = 360;
2359                 mouse[0]-= WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value);
2360                 mouse[1]-= WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value);
2361                 initial_value *= 180.0f/M_PI;
2362         }
2363
2364         if(op->customdata) {
2365                 ImBuf *im = (ImBuf*)op->customdata;
2366                 /* Build GL texture */
2367                 glGenTextures(1, &rc->tex);
2368                 glBindTexture(GL_TEXTURE_2D, rc->tex);
2369                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, im->x, im->y, 0, GL_ALPHA, GL_FLOAT, im->rect_float);
2370                 MEM_freeN(im->rect_float);
2371                 MEM_freeN(im);
2372         }
2373
2374         RNA_int_set_array(op->ptr, "initial_mouse", mouse);
2375         RNA_float_set(op->ptr, "new_value", initial_value);
2376                 
2377         op->customdata = rc;
2378         rc->mode = mode;
2379         rc->initial_value = initial_value;
2380         rc->initial_mouse[0] = mouse[0];
2381         rc->initial_mouse[1] = mouse[1];
2382         rc->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), op->type->poll,
2383                                               wm_radial_control_paint, op->customdata);
2384
2385         /* add modal handler */
2386         WM_event_add_modal_handler(C, op);
2387         
2388         WM_radial_control_modal(C, op, event);
2389         
2390         return OPERATOR_RUNNING_MODAL;
2391 }
2392
2393 /* Gets a descriptive string of the operation */
2394 void WM_radial_control_string(wmOperator *op, char str[], int maxlen)
2395 {
2396         int mode = RNA_int_get(op->ptr, "mode");
2397         float v = RNA_float_get(op->ptr, "new_value");
2398
2399         if(mode == WM_RADIALCONTROL_SIZE)
2400                 sprintf(str, "Size: %d", (int)v);
2401         else if(mode == WM_RADIALCONTROL_STRENGTH)
2402                 sprintf(str, "Strength: %d", (int)v);
2403         else if(mode == WM_RADIALCONTROL_ANGLE)
2404                 sprintf(str, "Angle: %d", (int)(v * 180.0f/M_PI));
2405 }
2406
2407 /** Important: this doesn't define an actual operator, it
2408     just sets up the common parts of the radial control op. **/
2409 void WM_OT_radial_control_partial(wmOperatorType *ot)
2410 {
2411         static EnumPropertyItem radial_mode_items[] = {
2412                 {WM_RADIALCONTROL_SIZE, "SIZE", 0, "Size", ""},
2413                 {WM_RADIALCONTROL_STRENGTH, "STRENGTH", 0, "Strength", ""},
2414                 {WM_RADIALCONTROL_ANGLE, "ANGLE", 0, "Angle", ""},
2415                 {0, NULL, 0, NULL, NULL}};
2416
2417         /* Should be set in custom invoke() */
2418         RNA_def_float(ot->srna, "initial_value", 0, 0, FLT_MAX, "Initial Value", "", 0, FLT_MAX);
2419
2420         /* Set internally, should be used in custom exec() to get final value */
2421         RNA_def_float(ot->srna, "new_value", 0, 0, FLT_MAX, "New Value", "", 0, FLT_MAX);
2422
2423         /* Should be set before calling operator */
2424         RNA_def_enum(ot->srna, "mode", radial_mode_items, 0, "Mode", "");
2425
2426         /* Internal */
2427         RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
2428 }
2429
2430 /* ************************** timer for testing ***************** */
2431
2432 /* uses no type defines, fully local testing function anyway... ;) */
2433
2434 static int redraw_timer_exec(bContext *C, wmOperator *op)
2435 {
2436         ARegion *ar= CTX_wm_region(C);
2437         double stime= PIL_check_seconds_timer();
2438         int type = RNA_int_get(op->ptr, "type");
2439         int iter = RNA_int_get(op->ptr, "iterations");
2440         int a;
2441         float time;
2442         char *infostr= "";
2443         
2444         WM_cursor_wait(1);
2445
2446         for(a=0; a<iter; a++) {
2447                 if (type==0) {
2448                         ED_region_do_draw(C, ar);
2449                 } 
2450                 else if (type==1) {
2451                         wmWindow *win= CTX_wm_window(C);
2452                         
2453                         ED_region_tag_redraw(ar);
2454                         wm_draw_update(C);
2455                         
2456                         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
2457                 }
2458                 else if (type==2) {
2459                         wmWindow *win= CTX_wm_window(C);
2460                         ScrArea *sa;
2461                         
2462                         ScrArea *sa_back= CTX_wm_area(C);
2463                         ARegion *ar_back= CTX_wm_region(C);
2464
2465                         for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) {
2466                                 ARegion *ar_iter;
2467                                 CTX_wm_area_set(C, sa);
2468
2469                                 for(ar_iter= sa->regionbase.first; ar_iter; ar_iter= ar_iter->next) {
2470                                         CTX_wm_region_set(C, ar_iter);
2471                                         ED_region_do_draw(C, ar_iter);
2472                                 }
2473                         }
2474
2475                         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
2476
2477                         CTX_wm_area_set(C, sa_back);
2478                         CTX_wm_region_set(C, ar_back);
2479                 }
2480                 else if (type==3) {
2481                         wmWindow *win= CTX_wm_window(C);
2482                         ScrArea *sa;
2483
2484                         for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next)
2485                                 ED_area_tag_redraw(sa);
2486                         wm_draw_update(C);
2487                         
2488                         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
2489                 }
2490                 else if (type==4) {
2491                         Scene *scene= CTX_data_scene(C);
2492                         
2493                         if(a & 1) scene->r.cfra--;
2494                         else scene->r.cfra++;
2495                         scene_update_for_newframe(scene, scene->lay);
2496                 }
2497                 else {
2498                         ED_undo_pop(C);
2499                         ED_undo_redo(C);
2500                 }
2501         }
2502         
2503         time= ((PIL_check_seconds_timer()-stime)*1000);
2504         
2505         if(type==0) infostr= "Draw Region";
2506         if(type==1) infostr= "Draw Region and Swap";
2507         if(type==2) infostr= "Draw Window";
2508         if(type==3) infostr= "Draw Window and Swap";
2509         if(type==4) infostr= "Animation Steps";
2510         if(type==5) infostr= "Undo/Redo";
2511         
2512         WM_cursor_wait(0);
2513         
2514         BKE_reportf(op->reports, RPT_INFO, "%d x %s: %.2f ms,  average: %.4f", iter, infostr, time, time/iter);
2515         
2516         return OPERATOR_FINISHED;
2517 }
2518
2519 static void WM_OT_redraw_timer(wmOperatorType *ot)
2520 {
2521         static EnumPropertyItem prop_type_items[] = {
2522         {0, "DRAW", 0, "Draw Region", ""},
2523         {1, "DRAW_SWAP", 0, "Draw Region + Swap", ""},
2524         {2, "DRAW_WIN", 0, "Draw Window", ""},
2525         {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", ""},
2526         {4, "ANIM_STEP", 0, "Anim Step", ""},
2527         {5, "UNDO", 0, "Undo/Redo", ""},
2528         {0, NULL, 0, NULL, NULL}};
2529         
2530         ot->name= "Redraw Timer";
2531         ot->idname= "WM_OT_redraw_timer";
2532         ot->description="Simple redraw timer to test the speed of updating the interface.";
2533         
2534         ot->invoke= WM_menu_invoke;
2535         ot->exec= redraw_timer_exec;
2536         ot->poll= WM_operator_winactive;
2537         
2538         RNA_def_enum(ot->srna, "type", prop_type_items, 0, "Type", "");
2539         RNA_def_int(ot->srna, "iterations", 10, 1,INT_MAX, "Iterations", "Number of times to redraw", 1,1000);
2540
2541 }
2542
2543 /* ************************** memory statistics for testing ***************** */
2544
2545 static int memory_statistics_exec(bContext *C, wmOperator *op)
2546 {
2547         MEM_printmemlist_stats();
2548         return OPERATOR_FINISHED;
2549 }
2550
2551 static void WM_OT_memory_statistics(wmOperatorType *ot)
2552 {
2553         ot->name= "Memory Statistics";
2554         ot->idname= "WM_OT_memory_statistics";
2555         ot->description= "Print memory statistics to the console.";
2556         
2557         ot->exec= memory_statistics_exec;
2558 }
2559
2560 /* ******************************************************* */
2561  
2562 /* called on initialize WM_exit() */
2563 void wm_operatortype_free(void)
2564 {
2565         wmOperatorType *ot;
2566         
2567         for(ot= global_ops.first; ot; ot= ot->next)
2568                 if(ot->macro.first)
2569                         wm_operatortype_free_macro(ot);
2570         
2571         BLI_freelistN(&global_ops);
2572 }
2573
2574 /* called on initialize WM_init() */
2575 void wm_operatortype_init(void)
2576 {
2577         WM_operatortype_append(WM_OT_window_duplicate);
2578         WM_operatortype_append(WM_OT_read_homefile);
2579         WM_operatortype_append(WM_OT_save_homefile);
2580         WM_operatortype_append(WM_OT_window_fullscreen_toggle);
2581         WM_operatortype_append(WM_OT_exit_blender);
2582         WM_operatortype_append(WM_OT_open_recentfile);
2583         WM_operatortype_append(WM_OT_open_recentfile_splash);
2584         WM_operatortype_append(WM_OT_open_mainfile);
2585         WM_operatortype_append(WM_OT_link_append);
2586         WM_operatortype_append(WM_OT_recover_last_session);
2587         WM_operatortype_append(WM_OT_recover_auto_save);
2588         WM_operatortype_append(WM_OT_save_as_mainfile);
2589         WM_operatortype_append(WM_OT_save_mainfile);
2590         WM_operatortype_append(WM_OT_redraw_timer);
2591         WM_operatortype_append(WM_OT_memory_statistics);
2592         WM_operatortype_append(WM_OT_debug_menu);
2593         WM_operatortype_append(WM_OT_splash);
2594         WM_operatortype_append(WM_OT_search_menu);
2595         WM_operatortype_append(WM_OT_call_menu);
2596
2597 #ifdef WITH_COLLADA
2598         /* XXX: move these */
2599         WM_operatortype_append(WM_OT_collada_export);
2600         WM_operatortype_append(WM_OT_collada_import);
2601 #endif
2602
2603 }
2604
2605 /* called in transform_ops.c, on each regeneration of keymaps  */
2606 static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
2607 {
2608         static EnumPropertyItem modal_items[] = {
2609         {GESTURE_MODAL_CANCEL,  "CANCEL", 0, "Cancel", ""},
2610         {GESTURE_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
2611         {GESTURE_MODAL_CIRCLE_ADD, "ADD", 0, "Add", ""},
2612         {GESTURE_MODAL_CIRCLE_SUB, "SUBTRACT", 0, "Subtract", ""},
2613
2614         {GESTURE_MODAL_SELECT,  "SELECT", 0, "Select", ""},
2615         {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""},
2616         {GESTURE_MODAL_NOP,"NOP", 0, "No Operation", ""},
2617
2618
2619         {0, NULL, 0, NULL, NULL}};
2620
2621         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Gesture Circle");
2622
2623         /* this function is called for each spacetype, only needs to add map once */
2624         if(keymap) return;
2625
2626         keymap= WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items);
2627
2628         /* items for modal map */
2629         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
2630         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
2631
2632         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CONFIRM);
2633         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, 0, 0, GESTURE_MODAL_CONFIRM);
2634
2635         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_SELECT);
2636
2637 #if 0 // Durien guys like this :S
2638         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
2639         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_NOP);
2640 #else
2641         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_DESELECT); //  defailt 2.4x
2642         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); //  defailt 2.4x
2643 #endif
2644
2645         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP);
2646
2647         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
2648         WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
2649         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
2650         WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
2651
2652         /* assign map to operators */
2653         WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle");
2654         WM_modalkeymap_assign(keymap, "UV_OT_circle_select");
2655
2656 }
2657
2658 /* called in transform_ops.c, on each regeneration of keymaps  */
2659 static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
2660 {
2661         static EnumPropertyItem modal_items[] = {
2662         {GESTURE_MODAL_CANCEL,  "CANCEL", 0, "Cancel", ""},
2663         {GESTURE_MODAL_SELECT,  "SELECT", 0, "Select", ""},
2664         {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""},
2665         {GESTURE_MODAL_BORDER_BEGIN,    "BEGIN", 0, "Begin", ""},
2666         {0, NULL, 0, NULL, NULL}};
2667
2668         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Border");
2669
2670         /* this function is called for each spacetype, only needs to add map once */
2671         if(keymap) return;
2672
2673         keymap= WM_modalkeymap_add(keyconf, "Gesture Border", modal_items);
2674
2675         /* items for modal map */
2676         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
2677         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
2678
2679         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BORDER_BEGIN);
2680         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_SELECT);
2681
2682 #if 0 // Durian guys like this
2683         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_BORDER_BEGIN);
2684         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
2685 #else
2686         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BORDER_BEGIN);
2687         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT);
2688 #endif
2689
2690         /* assign map to operators */
2691         WM_modalkeymap_assign(keymap, "ACTION_OT_select_border");
2692         WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border");
2693         WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set");
2694         WM_modalkeymap_assign(keymap, "CONSOLE_OT_select_border");
2695         WM_modalkeymap_assign(keymap, "FILE_OT_select_border");
2696         WM_modalkeymap_assign(keymap, "GRAPH_OT_select_border");
2697         WM_modalkeymap_assign(keymap, "MARKER_OT_select_border");
2698         WM_modalkeymap_assign(keymap, "NLA_OT_select_border");
2699         WM_modalkeymap_assign(keymap, "NODE_OT_select_border");
2700 //      WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template
2701         WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border");
2702         WM_modalkeymap_assign(keymap, "UV_OT_select_border");
2703         WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
2704         WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
2705         WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
2706         WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
2707         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); // XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel
2708 }
2709
2710 /* default keymap for windows and screens, only call once per WM */
2711 void wm_window_keymap(wmKeyConfig *keyconf)
2712 {
2713         wmKeyMap *keymap= WM_keymap_find(keyconf, "Window", 0, 0);
2714         wmKeyMapItem *km;
2715         
2716         /* note, this doesn't replace existing keymap items */
2717         WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2718         #ifdef __APPLE__
2719         WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_OSKEY, 0);
2720         WM_keymap_add_item(keymap, "WM_OT_open_recentfile", OKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2721         WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_OSKEY, 0);
2722         WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_OSKEY, 0);
2723         WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2724         WM_keymap_add_item(keymap, "WM_OT_exit_blender", QKEY, KM_PRESS, KM_OSKEY, 0);
2725         #endif
2726         WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0);
2727         WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); 
2728         WM_keymap_add_item(keymap, "WM_OT_open_recentfile", OKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2729         WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0);
2730         WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
2731         WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2732         km= WM_keymap_add_item(keymap, "WM_OT_link_append", F1KEY, KM_PRESS, KM_SHIFT, 0);
2733         RNA_boolean_set(km->ptr, "link", FALSE);
2734
2735         WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0);
2736         WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0);
2737         WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2738         WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", F2KEY, KM_PRESS, 0, 0);
2739
2740         WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0);
2741         WM_keymap_add_item(keymap, "WM_OT_exit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
2742
2743         /* debug/testing */
2744         WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
2745         WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
2746         WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
2747         
2748         /* Space switching */
2749
2750
2751         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
2752         RNA_string_set(km->ptr, "path", "area.type");
2753         RNA_string_set(km->ptr, "value", "LOGIC_EDITOR");
2754
2755         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F3KEY, KM_PRESS, KM_SHIFT, 0);
2756         RNA_string_set(km->ptr, "path", "area.type");
2757         RNA_string_set(km->ptr, "value", "NODE_EDITOR");
2758
2759         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F4KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was data browser */
2760         RNA_string_set(km->ptr, "path", "area.type");
2761         RNA_string_set(km->ptr, "value", "CONSOLE");
2762
2763         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F5KEY, KM_PRESS, KM_SHIFT, 0);
2764         RNA_string_set(km->ptr, "path", "area.type");
2765         RNA_string_set(km->ptr, "value", "VIEW_3D");
2766
2767         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F6KEY, KM_PRESS, KM_SHIFT, 0);
2768         RNA_string_set(km->ptr, "path", "area.type");
2769         RNA_string_set(km->ptr, "value", "GRAPH_EDITOR");
2770
2771         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F7KEY, KM_PRESS, KM_SHIFT, 0);
2772         RNA_string_set(km->ptr, "path", "area.type");
2773         RNA_string_set(km->ptr, "value", "PROPERTIES");
2774
2775         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F8KEY, KM_PRESS, KM_SHIFT, 0);
2776         RNA_string_set(km->ptr, "path", "area.type");
2777         RNA_string_set(km->ptr, "value", "SEQUENCE_EDITOR");
2778
2779         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F9KEY, KM_PRESS, KM_SHIFT, 0);
2780         RNA_string_set(km->ptr, "path", "area.type");
2781         RNA_string_set(km->ptr, "value", "OUTLINER");
2782
2783         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F9KEY, KM_PRESS, KM_SHIFT, 0);
2784         RNA_string_set(km->ptr, "path", "area.type");
2785         RNA_string_set(km->ptr, "value", "OUTLINER");
2786
2787         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F10KEY, KM_PRESS, KM_SHIFT, 0);
2788         RNA_string_set(km->ptr, "path", "area.type");
2789         RNA_string_set(km->ptr, "value", "IMAGE_EDITOR");
2790
2791         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F11KEY, KM_PRESS, KM_SHIFT, 0);
2792         RNA_string_set(km->ptr, "path", "area.type");
2793         RNA_string_set(km->ptr, "value", "TEXT_EDITOR");
2794
2795         km = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F12KEY, KM_PRESS, KM_SHIFT, 0);
2796         RNA_string_set(km->ptr, "path", "area.type");
2797         RNA_string_set(km->ptr, "value", "DOPESHEET_EDITOR");
2798
2799         gesture_circle_modal_keymap(keyconf);
2800         gesture_border_modal_keymap(keyconf);
2801 }
2802
2803 /* Generic itemf's for operators that take library args */
2804 static EnumPropertyItem *rna_id_itemf(bContext *C, PointerRNA *ptr, int *free, ID *id)
2805 {
2806         EnumPropertyItem *item= NULL, item_tmp;
2807         int totitem= 0;
2808         int i= 0;
2809
2810         memset(&item_tmp, 0, sizeof(item_tmp));
2811
2812         for( ; id; id= id->next) {
2813                 item_tmp.identifier= item_tmp.name= id->name+2;
2814                 item_tmp.value= i++;
2815                 RNA_enum_item_add(&item, &totitem, &item_tmp);
2816         }
2817
2818         RNA_enum_item_end(&item, &totitem);
2819         *free= 1;
2820
2821         return item;
2822 }
2823
2824 /* can add more */
2825 EnumPropertyItem *RNA_group_itemf(bContext *C, PointerRNA *ptr, int *free)
2826 {
2827         return rna_id_itemf(C, ptr, free, (ID *)CTX_data_main(C)->group.first);
2828 }
2829 EnumPropertyItem *RNA_scene_itemf(bContext *C, PointerRNA *ptr, int *free)
2830 {
2831         return rna_id_itemf(C, ptr, free, (ID *)CTX_data_main(C)->scene.first);
2832 }