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