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