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