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