=trunk=
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/windowmanager/intern/wm_operators.c
30  *  \ingroup wm
31  */
32
33
34 #include <float.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stddef.h>
39 #include <assert.h>
40
41 #include "GHOST_C-api.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_ID.h"
46 #include "DNA_object_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_userdef_types.h"
50 #include "DNA_windowmanager_types.h"
51
52 #include "BLF_api.h"
53
54 #include "PIL_time.h"
55
56 #include "BLI_blenlib.h"
57 #include "BLI_dynstr.h" /*for WM_operator_pystring */
58 #include "BLI_math.h"
59 #include "BLI_utildefines.h"
60
61 #include "BLO_readfile.h"
62
63 #include "BKE_blender.h"
64 #include "BKE_context.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_idprop.h"
67 #include "BKE_library.h"
68 #include "BKE_global.h"
69 #include "BKE_main.h"
70 #include "BKE_report.h"
71 #include "BKE_scene.h"
72 #include "BKE_screen.h" /* BKE_ST_MAXNAME */
73
74 #include "BKE_idcode.h"
75
76 #include "BIF_gl.h"
77 #include "BIF_glutil.h" /* for paint cursor */
78
79 #include "IMB_imbuf_types.h"
80
81 #include "ED_screen.h"
82 #include "ED_util.h"
83
84 #include "RNA_access.h"
85 #include "RNA_define.h"
86 #include "RNA_enum_types.h"
87
88 #include "UI_interface.h"
89 #include "UI_resources.h"
90
91 #include "WM_api.h"
92 #include "WM_types.h"
93
94 #include "wm.h"
95 #include "wm_draw.h"
96 #include "wm_event_system.h"
97 #include "wm_event_types.h"
98 #include "wm_subwindow.h"
99 #include "wm_window.h"
100
101 static ListBase global_ops= {NULL, NULL};
102
103 /* ************ operator API, exported ********** */
104
105
106 wmOperatorType *WM_operatortype_find(const char *idname, int quiet)
107 {
108         wmOperatorType *ot;
109         
110         char idname_bl[OP_MAX_TYPENAME]; // XXX, needed to support python style names without the _OT_ syntax
111         WM_operator_bl_idname(idname_bl, idname);
112
113         if (idname_bl[0]) {
114                 ot= (wmOperatorType *)BLI_findstring_ptr(&global_ops, idname_bl, offsetof(wmOperatorType, idname));
115                 if(ot) {
116                         return ot;
117                 }
118         }
119         
120         if(!quiet)
121                 printf("search for unknown operator %s, %s\n", idname_bl, idname);
122         
123         return NULL;
124 }
125
126 wmOperatorType *WM_operatortype_first(void)
127 {
128         return global_ops.first;
129 }
130
131 /* all ops in 1 list (for time being... needs evaluation later) */
132 void WM_operatortype_append(void (*opfunc)(wmOperatorType*))
133 {
134         wmOperatorType *ot;
135         
136         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
137         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
138         opfunc(ot);
139
140         if(ot->name==NULL) {
141                 static char dummy_name[] = "Dummy Name";
142                 fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
143                 ot->name= dummy_name;
144         }
145
146         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.
147         RNA_def_struct_identifier(ot->srna, ot->idname);
148         BLI_addtail(&global_ops, ot);
149 }
150
151 void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata)
152 {
153         wmOperatorType *ot;
154
155         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
156         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
157         opfunc(ot, userdata);
158         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)");
159         RNA_def_struct_identifier(ot->srna, ot->idname);
160         BLI_addtail(&global_ops, ot);
161 }
162
163 /* ********************* macro operator ******************** */
164
165 typedef struct {
166         int retval;
167 } MacroData;
168
169 static void wm_macro_start(wmOperator *op)
170 {
171         if (op->customdata == NULL) {
172                 op->customdata = MEM_callocN(sizeof(MacroData), "MacroData");
173         }
174 }
175
176 static int wm_macro_end(wmOperator *op, int retval)
177 {
178         if (retval & OPERATOR_CANCELLED) {
179                 MacroData *md = op->customdata;
180
181                 if (md->retval & OPERATOR_FINISHED) {
182                         retval |= OPERATOR_FINISHED;
183                         retval &= ~OPERATOR_CANCELLED;
184                 }
185         }
186
187         /* if modal is ending, free custom data */
188         if (retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED)) {
189                 if (op->customdata) {
190                         MEM_freeN(op->customdata);
191                         op->customdata = NULL;
192                 }
193         }
194
195         return retval;
196 }
197
198 /* macro exec only runs exec calls */
199 static int wm_macro_exec(bContext *C, wmOperator *op)
200 {
201         wmOperator *opm;
202         int retval= OPERATOR_FINISHED;
203         
204         wm_macro_start(op);
205
206         for(opm= op->macro.first; opm; opm= opm->next) {
207                 
208                 if(opm->type->exec) {
209                         retval= opm->type->exec(C, opm);
210                 
211                         if (retval & OPERATOR_FINISHED) {
212                                 MacroData *md = op->customdata;
213                                 md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
214                         } else {
215                                 break; /* operator didn't finish, end macro */
216                         }
217                         
218                         if (retval & OPERATOR_ABORT_MACRO)
219                                 break;
220                 }
221         }
222         
223         return wm_macro_end(op, retval);
224 }
225
226 static int wm_macro_invoke_internal(bContext *C, wmOperator *op, wmEvent *event, wmOperator *opm)
227 {
228         int retval= OPERATOR_FINISHED;
229
230         /* start from operator received as argument */
231         for( ; opm; opm= opm->next) {
232                 if(opm->type->invoke)
233                         retval= opm->type->invoke(C, opm, event);
234                 else if(opm->type->exec)
235                         retval= opm->type->exec(C, opm);
236
237                 BLI_movelisttolist(&op->reports->list, &opm->reports->list);
238                 
239                 if (retval & OPERATOR_FINISHED) {
240                         MacroData *md = op->customdata;
241                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
242                 } else {
243                         break; /* operator didn't finish, end macro */
244                 }
245                 
246                 if (retval & OPERATOR_ABORT_MACRO)
247                         break;
248         }
249
250         return wm_macro_end(op, retval);
251 }
252
253 static int wm_macro_invoke(bContext *C, wmOperator *op, wmEvent *event)
254 {
255         wm_macro_start(op);
256         return wm_macro_invoke_internal(C, op, event, op->macro.first);
257 }
258
259 static int wm_macro_modal(bContext *C, wmOperator *op, wmEvent *event)
260 {
261         wmOperator *opm = op->opm;
262         int retval= OPERATOR_FINISHED;
263         
264         if(opm==NULL)
265                 printf("macro error, calling NULL modal()\n");
266         else {
267                 retval = opm->type->modal(C, opm, event);
268
269                 /* if this one is done but it's not the last operator in the macro */
270                 if ((retval & OPERATOR_FINISHED) && opm->next) {
271                         MacroData *md = op->customdata;
272
273                         md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */
274                         
275                         if (!(retval & OPERATOR_ABORT_MACRO)) {
276                                 retval = wm_macro_invoke_internal(C, op, event, opm->next);
277         
278                                 /* if new operator is modal and also added its own handler */
279                                 if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) {
280                                         wmWindow *win = CTX_wm_window(C);
281                                         wmEventHandler *handler = NULL;
282         
283                                         for (handler = win->modalhandlers.first; handler; handler = handler->next) {
284                                                 /* first handler in list is the new one */
285                                                 if (handler->op == op)
286                                                         break;
287                                         }
288         
289                                         if (handler) {
290                                                 BLI_remlink(&win->modalhandlers, handler);
291                                                 wm_event_free_handler(handler);
292                                         }
293         
294                                         /* if operator is blocking, grab cursor
295                                          * This may end up grabbing twice, but we don't care.
296                                          * */
297                                         if(op->opm->type->flag & OPTYPE_BLOCKING) {
298                                                 int bounds[4] = {-1,-1,-1,-1};
299                                                 int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER));
300         
301                                                 if(wrap) {
302                                                         ARegion *ar= CTX_wm_region(C);
303                                                         if(ar) {
304                                                                 bounds[0]= ar->winrct.xmin;
305                                                                 bounds[1]= ar->winrct.ymax;
306                                                                 bounds[2]= ar->winrct.xmax;
307                                                                 bounds[3]= ar->winrct.ymin;
308                                                         }
309                                                 }
310         
311                                                 WM_cursor_grab(CTX_wm_window(C), wrap, FALSE, bounds);
312                                         }
313                                 }
314                         }
315                 }
316         }
317
318         return wm_macro_end(op, retval);
319 }
320
321 static int wm_macro_cancel(bContext *C, wmOperator *op)
322 {
323         /* call cancel on the current modal operator, if any */
324         if (op->opm && op->opm->type->cancel) {
325                 op->opm->type->cancel(C, op->opm);
326         }
327
328         return wm_macro_end(op, OPERATOR_CANCELLED);
329 }
330
331 /* Names have to be static for now */
332 wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, int flag)
333 {
334         wmOperatorType *ot;
335         
336         if(WM_operatortype_find(idname, TRUE)) {
337                 printf("Macro error: operator %s exists\n", idname);
338                 return NULL;
339         }
340         
341         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
342         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
343         
344         ot->idname= idname;
345         ot->name= name;
346         ot->flag= OPTYPE_MACRO|flag;
347         
348         ot->exec= wm_macro_exec;
349         ot->invoke= wm_macro_invoke;
350         ot->modal= wm_macro_modal;
351         ot->cancel= wm_macro_cancel;
352         ot->poll= NULL;
353
354         if(!ot->description)
355                 ot->description= "(undocumented operator)";
356         
357         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); // XXX All ops should have a description but for now allow them not to.
358         RNA_def_struct_identifier(ot->srna, ot->idname);
359
360         BLI_addtail(&global_ops, ot);
361
362         return ot;
363 }
364
365 void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata)
366 {
367         wmOperatorType *ot;
368
369         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
370         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
371
372         ot->flag= OPTYPE_MACRO;
373         ot->exec= wm_macro_exec;
374         ot->invoke= wm_macro_invoke;
375         ot->modal= wm_macro_modal;
376         ot->cancel= wm_macro_cancel;
377         ot->poll= NULL;
378
379         if(!ot->description)
380                 ot->description= "(undocumented operator)";
381
382         opfunc(ot, userdata);
383
384         RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
385         RNA_def_struct_identifier(ot->srna, ot->idname);
386
387         BLI_addtail(&global_ops, ot);
388 }
389
390 wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
391 {
392         wmOperatorTypeMacro *otmacro= MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
393
394         BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
395
396         /* do this on first use, since operatordefinitions might have been not done yet */
397         WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname);
398         WM_operator_properties_sanitize(otmacro->ptr, 1);
399
400         BLI_addtail(&ot->macro, otmacro);
401
402         {
403                 /* operator should always be found but in the event its not. dont segfault */
404                 wmOperatorType *otsub = WM_operatortype_find(idname, 0);
405                 if(otsub) {
406                         RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna,
407                         otsub->name, otsub->description);
408                 }
409         }
410
411         return otmacro;
412 }
413
414 static void wm_operatortype_free_macro(wmOperatorType *ot)
415 {
416         wmOperatorTypeMacro *otmacro;
417         
418         for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
419                 if(otmacro->ptr) {
420                         WM_operator_properties_free(otmacro->ptr);
421                         MEM_freeN(otmacro->ptr);
422                 }
423         }
424         BLI_freelistN(&ot->macro);
425 }
426
427
428 int WM_operatortype_remove(const char *idname)
429 {
430         wmOperatorType *ot = WM_operatortype_find(idname, 0);
431
432         if (ot==NULL)
433                 return 0;
434         
435         BLI_remlink(&global_ops, ot);
436         RNA_struct_free(&BLENDER_RNA, ot->srna);
437         
438         if(ot->macro.first)
439                 wm_operatortype_free_macro(ot);
440         
441         MEM_freeN(ot);
442
443         return 1;
444 }
445
446 /* SOME_OT_op -> some.op */
447 void WM_operator_py_idname(char *to, const char *from)
448 {
449         char *sep= strstr(from, "_OT_");
450         if(sep) {
451                 int i, ofs= (sep-from);
452
453                 for(i=0; i<ofs; i++)
454                         to[i]= tolower(from[i]);
455
456                 to[ofs] = '.';
457                 BLI_strncpy(to+(ofs+1), sep+4, OP_MAX_TYPENAME);
458         }
459         else {
460                 /* should not happen but support just incase */
461                 BLI_strncpy(to, from, OP_MAX_TYPENAME);
462         }
463 }
464
465 /* some.op -> SOME_OT_op */
466 void WM_operator_bl_idname(char *to, const char *from)
467 {
468         if (from) {
469                 char *sep= strchr(from, '.');
470
471                 if(sep) {
472                         int i, ofs= (sep-from);
473
474                         for(i=0; i<ofs; i++)
475                                 to[i]= toupper(from[i]);
476
477                         BLI_strncpy(to+ofs, "_OT_", OP_MAX_TYPENAME);
478                         BLI_strncpy(to+(ofs+4), sep+1, OP_MAX_TYPENAME);
479                 }
480                 else {
481                         /* should not happen but support just incase */
482                         BLI_strncpy(to, from, OP_MAX_TYPENAME);
483                 }
484         }
485         else
486                 to[0]= 0;
487 }
488
489 /* print a string representation of the operator, with the args that it runs 
490  * so python can run it again,
491  *
492  * When calling from an existing wmOperator do.
493  * WM_operator_pystring(op->type, op->ptr);
494  */
495 char *WM_operator_pystring(bContext *C, wmOperatorType *ot, PointerRNA *opptr, int all_args)
496 {
497         const char *arg_name= NULL;
498         char idname_py[OP_MAX_TYPENAME];
499
500         PropertyRNA *prop, *iterprop;
501
502         /* for building the string */
503         DynStr *dynstr= BLI_dynstr_new();
504         char *cstring, *buf;
505         int first_iter=1, ok= 1;
506
507
508         /* only to get the orginal props for comparisons */
509         PointerRNA opptr_default;
510         PropertyRNA *prop_default;
511         char *buf_default;
512         if(all_args==0 || opptr==NULL) {
513                 WM_operator_properties_create_ptr(&opptr_default, ot);
514
515                 if(opptr==NULL)
516                         opptr = &opptr_default;
517         }
518
519
520         WM_operator_py_idname(idname_py, ot->idname);
521         BLI_dynstr_appendf(dynstr, "bpy.ops.%s(", idname_py);
522
523         iterprop= RNA_struct_iterator_property(opptr->type);
524
525         RNA_PROP_BEGIN(opptr, propptr, iterprop) {
526                 prop= propptr.data;
527                 arg_name= RNA_property_identifier(prop);
528
529                 if (strcmp(arg_name, "rna_type")==0) continue;
530
531                 buf= RNA_property_as_string(C, opptr, prop);
532                 
533                 ok= 1;
534
535                 if(!all_args) {
536                         /* not verbose, so only add in attributes that use non-default values
537                          * slow but good for tooltips */
538                         prop_default= RNA_struct_find_property(&opptr_default, arg_name);
539
540                         if(prop_default) {
541                                 buf_default= RNA_property_as_string(C, &opptr_default, prop_default);
542
543                                 if(strcmp(buf, buf_default)==0)
544                                         ok= 0; /* values match, dont bother printing */
545
546                                 MEM_freeN(buf_default);
547                         }
548
549                 }
550                 if(ok) {
551                         BLI_dynstr_appendf(dynstr, first_iter?"%s=%s":", %s=%s", arg_name, buf);
552                         first_iter = 0;
553                 }
554
555                 MEM_freeN(buf);
556
557         }
558         RNA_PROP_END;
559
560         if(all_args==0 || opptr==&opptr_default )
561                 WM_operator_properties_free(&opptr_default);
562
563         BLI_dynstr_append(dynstr, ")");
564
565         cstring = BLI_dynstr_get_cstring(dynstr);
566         BLI_dynstr_free(dynstr);
567         return cstring;
568 }
569
570 void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
571 {
572         RNA_pointer_create(NULL, ot->srna, NULL, ptr);
573 }
574
575 void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
576 {
577         wmOperatorType *ot= WM_operatortype_find(opstring, 0);
578
579         if(ot)
580                 WM_operator_properties_create_ptr(ptr, ot);
581         else
582                 RNA_pointer_create(NULL, &RNA_OperatorProperties, NULL, ptr);
583 }
584
585 /* similar to the function above except its uses ID properties
586  * used for keymaps and macros */
587 void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
588 {
589         if(*properties==NULL) {
590                 IDPropertyTemplate val = {0};
591                 *properties= IDP_New(IDP_GROUP, val, "wmOpItemProp");
592         }
593
594         if(*ptr==NULL) {
595                 *ptr= MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
596                 WM_operator_properties_create(*ptr, opstring);
597         }
598
599         (*ptr)->data= *properties;
600
601 }
602
603 void WM_operator_properties_sanitize(PointerRNA *ptr, const short no_context)
604 {
605         RNA_STRUCT_BEGIN(ptr, prop) {
606                 switch(RNA_property_type(prop)) {
607                 case PROP_ENUM:
608                         if (no_context)
609                                 RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
610                         else
611                                 RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
612                         break;
613                 case PROP_POINTER:
614                         {
615                                 StructRNA *ptype= RNA_property_pointer_type(ptr, prop);
616
617                                 /* recurse into operator properties */
618                                 if (RNA_struct_is_a(ptype, &RNA_OperatorProperties)) {
619                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
620                                         WM_operator_properties_sanitize(&opptr, no_context);
621                                 }
622                                 break;
623                         }
624                 default:
625                         break;
626                 }
627         }
628         RNA_STRUCT_END;
629 }
630
631 void WM_operator_properties_free(PointerRNA *ptr)
632 {
633         IDProperty *properties= ptr->data;
634
635         if(properties) {
636                 IDP_FreeProperty(properties);
637                 MEM_freeN(properties);
638                 ptr->data= NULL; /* just incase */
639         }
640 }
641
642 /* ************ default op callbacks, exported *********** */
643
644 /* invoke callback, uses enum property named "type" */
645 int WM_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
646 {
647         PropertyRNA *prop= op->type->prop;
648         uiPopupMenu *pup;
649         uiLayout *layout;
650
651         if(prop==NULL) {
652                 printf("WM_menu_invoke: %s has no enum property set\n", op->type->idname);
653         }
654         else if (RNA_property_type(prop) != PROP_ENUM) {
655                 printf("WM_menu_invoke: %s \"%s\" is not an enum property\n", op->type->idname, RNA_property_identifier(prop));
656         }
657         else if (RNA_property_is_set(op->ptr, RNA_property_identifier(prop))) {
658                 return op->type->exec(C, op);
659         }
660         else {
661                 pup= uiPupMenuBegin(C, op->type->name, ICON_NONE);
662                 layout= uiPupMenuLayout(pup);
663                 uiItemsFullEnumO(layout, op->type->idname, (char*)RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0);
664                 uiPupMenuEnd(C, pup);
665         }
666
667         return OPERATOR_CANCELLED;
668 }
669
670
671 /* generic enum search invoke popup */
672 static void operator_enum_search_cb(const struct bContext *C, void *arg_ot, const char *str, uiSearchItems *items)
673 {
674         wmOperatorType *ot = (wmOperatorType *)arg_ot;
675         PropertyRNA *prop= ot->prop;
676
677         if(prop==NULL) {
678                 printf("WM_enum_search_invoke: %s has no enum property set\n", ot->idname);
679         }
680         else if (RNA_property_type(prop) != PROP_ENUM) {
681                 printf("WM_enum_search_invoke: %s \"%s\" is not an enum property\n", ot->idname, RNA_property_identifier(prop));
682         }
683         else {
684                 PointerRNA ptr;
685
686                 EnumPropertyItem *item, *item_array;
687                 int do_free;
688
689                 RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
690                 RNA_property_enum_items((bContext *)C, &ptr, prop, &item_array, NULL, &do_free);
691
692                 for(item= item_array; item->identifier; item++) {
693                         /* note: need to give the intex rather then the dientifier because the enum can be freed */
694                         if(BLI_strcasestr(item->name, str))
695                                 if(0==uiSearchItemAdd(items, item->name, SET_INT_IN_POINTER(item->value), 0))
696                                         break;
697                 }
698
699                 if(do_free)
700                         MEM_freeN(item_array);
701         }
702 }
703
704 static void operator_enum_call_cb(struct bContext *C, void *arg1, void *arg2)
705 {
706         wmOperatorType *ot= arg1;
707
708         if(ot) {
709                 PointerRNA props_ptr;
710                 WM_operator_properties_create_ptr(&props_ptr, ot);
711                 RNA_property_enum_set(&props_ptr, ot->prop, GET_INT_FROM_POINTER(arg2));
712                 WM_operator_name_call(C, ot->idname, WM_OP_EXEC_DEFAULT, &props_ptr);
713                 WM_operator_properties_free(&props_ptr);
714         }
715 }
716
717 static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
718 {
719         static char search[256]= "";
720         wmEvent event;
721         wmWindow *win= CTX_wm_window(C);
722         uiBlock *block;
723         uiBut *but;
724         wmOperator *op= (wmOperator *)arg_op;
725
726         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
727         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
728
729         //uiDefBut(block, LABEL, 0, op->type->name, 10, 10, 180, 19, NULL, 0.0, 0.0, 0, 0, ""); // ok, this isnt so easy...
730         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, 0, 0, "");
731         uiButSetSearchFunc(but, operator_enum_search_cb, op->type, operator_enum_call_cb, NULL);
732
733         /* fake button, it holds space for search items */
734         uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxhHeight(), 180, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
735
736         uiPopupBoundsBlock(block, 6, 0, -20); /* move it downwards, mouse over button */
737         uiEndBlock(C, block);
738
739         event= *(win->eventstate);      /* XXX huh huh? make api call */
740         event.type= EVT_BUT_OPEN;
741         event.val= KM_PRESS;
742         event.customdata= but;
743         event.customdatafree= FALSE;
744         wm_event_add(win, &event);
745
746         return block;
747 }
748
749
750 int WM_enum_search_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
751 {
752         uiPupBlock(C, wm_enum_search_menu, op);
753         return OPERATOR_CANCELLED;
754 }
755
756 /* Can't be used as an invoke directly, needs message arg (can be NULL) */
757 int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message)
758 {
759         uiPopupMenu *pup;
760         uiLayout *layout;
761         IDProperty *properties= op->ptr->data;
762
763         if(properties && properties->len)
764                 properties= IDP_CopyProperty(op->ptr->data);
765         else
766                 properties= NULL;
767
768         pup= uiPupMenuBegin(C, "OK?", ICON_QUESTION);
769         layout= uiPupMenuLayout(pup);
770         uiItemFullO(layout, op->type->idname, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0);
771         uiPupMenuEnd(C, pup);
772         
773         return OPERATOR_CANCELLED;
774 }
775
776
777 int WM_operator_confirm(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
778 {
779         return WM_operator_confirm_message(C, op, NULL);
780 }
781
782 /* op->invoke, opens fileselect if path property not set, otherwise executes */
783 int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
784 {
785         if (RNA_property_is_set(op->ptr, "filepath")) {
786                 return WM_operator_call(C, op);
787         } 
788         else {
789                 WM_event_add_fileselect(C, op);
790                 return OPERATOR_RUNNING_MODAL;
791         }
792 }
793
794 /* default properties for fileselect */
795 void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag)
796 {
797         PropertyRNA *prop;
798
799
800         if(flag & WM_FILESEL_FILEPATH)
801                 RNA_def_string_file_path(ot->srna, "filepath", "", FILE_MAX, "File Path", "Path to file");
802
803         if(flag & WM_FILESEL_DIRECTORY)
804                 RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Directory of the file");
805
806         if(flag & WM_FILESEL_FILENAME)
807                 RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "File Name", "Name of the file");
808
809         if (action == FILE_SAVE) {
810                 prop= RNA_def_boolean(ot->srna, "check_existing", 1, "Check Existing", "Check and warn on overwriting existing files");
811                 RNA_def_property_flag(prop, PROP_HIDDEN);
812         }
813         
814         prop= RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", "");
815         RNA_def_property_flag(prop, PROP_HIDDEN);
816         prop= RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", "");
817         RNA_def_property_flag(prop, PROP_HIDDEN);
818         prop= RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", "");
819         RNA_def_property_flag(prop, PROP_HIDDEN);
820         prop= RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", "");
821         RNA_def_property_flag(prop, PROP_HIDDEN);
822         prop= RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", "");
823         RNA_def_property_flag(prop, PROP_HIDDEN);
824         prop= RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", "");
825         RNA_def_property_flag(prop, PROP_HIDDEN);
826         prop= RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", "");
827         RNA_def_property_flag(prop, PROP_HIDDEN);
828         prop= RNA_def_boolean(ot->srna, "filter_btx", (filter & BTXFILE), "Filter btx files", "");
829         RNA_def_property_flag(prop, PROP_HIDDEN);
830         prop= RNA_def_boolean(ot->srna, "filter_collada", (filter & COLLADAFILE), "Filter COLLADA files", "");
831         RNA_def_property_flag(prop, PROP_HIDDEN);
832         prop= RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", "");
833         RNA_def_property_flag(prop, PROP_HIDDEN);
834
835         prop= RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, 
836                 "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
837                 FILE_LOADLIB, FILE_SPECIAL);
838         RNA_def_property_flag(prop, PROP_HIDDEN);
839
840         if(flag & WM_FILESEL_RELPATH)
841                 RNA_def_boolean(ot->srna, "relative_path", (U.flag & USER_RELPATHS) ? 1:0, "Relative Path", "Select the file relative to the blend file");
842 }
843
844 void WM_operator_properties_select_all(wmOperatorType *ot) {
845         static EnumPropertyItem select_all_actions[] = {
846                         {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
847                         {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
848                         {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
849                         {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
850                         {0, NULL, 0, NULL, NULL}
851         };
852
853         RNA_def_enum(ot->srna, "action", select_all_actions, SEL_TOGGLE, "Action", "Selection action to execute");
854 }
855
856 void WM_operator_properties_gesture_border(wmOperatorType *ot, int extend)
857 {
858         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
859         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
860         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
861         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
862         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
863
864         if(extend)
865                 RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
866 }
867
868 void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
869 {
870         RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX);
871         RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX);
872         RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX);
873         RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX);
874         
875         if(cursor)
876                 RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX, "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX);
877 }
878
879
880 /* op->poll */
881 int WM_operator_winactive(bContext *C)
882 {
883         if(CTX_wm_window(C)==NULL) return 0;
884         return 1;
885 }
886
887 static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
888 {
889         wmOperator *op= arg_op;
890         uiBlock *block;
891         uiLayout *layout;
892         uiStyle *style= U.uistyles.first;
893         int width= 300;
894         
895
896         block= uiBeginBlock(C, ar, "redo_popup", UI_EMBOSS);
897         uiBlockClearFlag(block, UI_BLOCK_LOOP);
898         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
899
900         /* if register is not enabled, the operator gets freed on OPERATOR_FINISHED
901          * ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */
902         assert(op->type->flag & OPTYPE_REGISTER);
903
904         uiBlockSetHandleFunc(block, ED_undo_operator_repeat_cb_evt, arg_op);
905         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, 20, style);
906
907         if(ED_undo_valid(C, op->type->name)==0)
908                 uiLayoutSetEnabled(layout, 0);
909
910         uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
911
912         uiPopupBoundsBlock(block, 4, 0, 0);
913         uiEndBlock(C, block);
914
915         return block;
916 }
917
918 /* Only invoked by OK button in popups created with wm_block_create_dialog() */
919 static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
920 {
921         wmOperator *op= arg1;
922         uiBlock *block= arg2;
923
924         WM_operator_call(C, op);
925
926         uiPupBlockClose(C, block);
927 }
928
929 static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
930 {
931         wmOperator *op= op_ptr;
932         if(op->type->check) {
933                 if(op->type->check(C, op)) {
934                         /* refresh */
935                 }
936         }
937 }
938
939 /* Dialogs are popups that require user verification (click OK) before exec */
940 static uiBlock *wm_block_create_dialog(bContext *C, ARegion *ar, void *userData)
941 {
942         struct { wmOperator *op; int width; int height; } * data = userData;
943         wmOperator *op= data->op;
944         uiBlock *block;
945         uiLayout *layout;
946         uiStyle *style= U.uistyles.first;
947
948         block = uiBeginBlock(C, ar, "operator dialog", UI_EMBOSS);
949         uiBlockClearFlag(block, UI_BLOCK_LOOP);
950         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
951
952         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, style);
953         
954         uiBlockSetFunc(block, dialog_check_cb, op, NULL);
955
956         uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
957         
958         /* clear so the OK button is left alone */
959         uiBlockSetFunc(block, NULL, NULL, NULL);
960
961         /* new column so as not to interfear with custom layouts [#26436] */
962         {
963                 uiBlock *col_block;
964                 uiLayout *col;
965                 uiBut *btn;
966
967                 col= uiLayoutColumn(layout, FALSE);
968                 col_block= uiLayoutGetBlock(col);
969                 /* Create OK button, the callback of which will execute op */
970                 btn= uiDefBut(col_block, BUT, 0, "OK", 0, -30, 0, 20, NULL, 0, 0, 0, 0, "");
971                 uiButSetFunc(btn, dialog_exec_cb, op, col_block);
972         }
973
974         /* center around the mouse */
975         uiPopupBoundsBlock(block, 4, data->width/-2, data->height/2);
976         uiEndBlock(C, block);
977
978         return block;
979 }
980
981 static uiBlock *wm_operator_create_ui(bContext *C, ARegion *ar, void *userData)
982 {
983         struct { wmOperator *op; int width; int height; } * data = userData;
984         wmOperator *op= data->op;
985         uiBlock *block;
986         uiLayout *layout;
987         uiStyle *style= U.uistyles.first;
988
989         block= uiBeginBlock(C, ar, "opui_popup", UI_EMBOSS);
990         uiBlockClearFlag(block, UI_BLOCK_LOOP);
991         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
992
993         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, style);
994
995         /* since ui is defined the auto-layout args are not used */
996         uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
997
998         uiPopupBoundsBlock(block, 4, 0, 0);
999         uiEndBlock(C, block);
1000
1001         return block;
1002 }
1003
1004 /* operator menu needs undo, for redo callback */
1005 int WM_operator_props_popup(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1006 {
1007         
1008         if((op->type->flag & OPTYPE_REGISTER)==0) {
1009                 BKE_reportf(op->reports, RPT_ERROR, "Operator '%s' does not have register enabled, incorrect invoke function.", op->type->idname);
1010                 return OPERATOR_CANCELLED;
1011         }
1012         
1013         ED_undo_push_op(C, op);
1014         wm_operator_register(C, op);
1015
1016         uiPupBlock(C, wm_block_create_redo, op);
1017
1018         return OPERATOR_RUNNING_MODAL;
1019 }
1020
1021 int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int height)
1022 {
1023         struct { wmOperator *op; int width; int height; } data;
1024         
1025         data.op= op;
1026         data.width= width;
1027         data.height= height;
1028
1029         /* op is not executed until popup OK but is clicked */
1030         uiPupBlock(C, wm_block_create_dialog, &data);
1031
1032         return OPERATOR_RUNNING_MODAL;
1033 }
1034
1035 int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
1036 {
1037         struct { wmOperator *op; int width; int height; } data;
1038         data.op = op;
1039         data.width = width;
1040         data.height = height;
1041         uiPupBlock(C, wm_operator_create_ui, &data);
1042         return OPERATOR_RUNNING_MODAL;
1043 }
1044
1045 int WM_operator_redo_popup(bContext *C, wmOperator *op)
1046 {
1047         /* CTX_wm_reports(C) because operator is on stack, not active in event system */
1048         if((op->type->flag & OPTYPE_REGISTER)==0) {
1049                 BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s' does not have register enabled, incorrect invoke function.", op->type->idname);
1050                 return OPERATOR_CANCELLED;
1051         }
1052         if(op->type->poll && op->type->poll(C)==0) {
1053                 BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Operator redo '%s': wrong context.", op->type->idname);
1054                 return OPERATOR_CANCELLED;
1055         }
1056         
1057         uiPupBlock(C, wm_block_create_redo, op);
1058
1059         return OPERATOR_CANCELLED;
1060 }
1061
1062 /* ***************** Debug menu ************************* */
1063
1064 static int wm_debug_menu_exec(bContext *C, wmOperator *op)
1065 {
1066         G.rt= RNA_int_get(op->ptr, "debug_value");
1067         ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
1068         WM_event_add_notifier(C, NC_WINDOW, NULL);
1069
1070         return OPERATOR_FINISHED;       
1071 }
1072
1073 static int wm_debug_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1074 {
1075         RNA_int_set(op->ptr, "debug_value", G.rt);
1076         return WM_operator_props_dialog_popup(C, op, 180, 20);
1077 }
1078
1079 static void WM_OT_debug_menu(wmOperatorType *ot)
1080 {
1081         ot->name= "Debug Menu";
1082         ot->idname= "WM_OT_debug_menu";
1083         ot->description= "Open a popup to set the debug level";
1084         
1085         ot->invoke= wm_debug_menu_invoke;
1086         ot->exec= wm_debug_menu_exec;
1087         ot->poll= WM_operator_winactive;
1088         
1089         RNA_def_int(ot->srna, "debug_value", 0, -10000, 10000, "Debug Value", "", INT_MIN, INT_MAX);
1090 }
1091
1092
1093 /* ***************** Splash Screen ************************* */
1094
1095 static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
1096 {
1097         uiPupBlockClose(C, arg_block);
1098 }
1099
1100 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused);
1101
1102 /* XXX: hack to refresh splash screen with updated prest menu name,
1103  * since popup blocks don't get regenerated like panels do */
1104 static void wm_block_splash_refreshmenu (bContext *UNUSED(C), void *UNUSED(arg_block), void *UNUSED(arg))
1105 {
1106         /* ugh, causes crashes in other buttons, disabling for now until 
1107          * a better fix
1108         uiPupBlockClose(C, arg_block);
1109         uiPupBlock(C, wm_block_create_splash, NULL);
1110           */
1111 }
1112
1113 static int wm_resource_check_prev(void)
1114 {
1115
1116         char *res= BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, TRUE);
1117
1118         // if(res) printf("USER: %s\n", res);
1119
1120 #if 0 /* ignore the local folder */
1121         if(res == NULL) {
1122                 /* with a local dir, copying old files isnt useful since local dir get priority for config */
1123                 res= BLI_get_folder_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, TRUE);
1124         }
1125 #endif
1126
1127         // if(res) printf("LOCAL: %s\n", res);
1128         if(res) {
1129                 return FALSE;
1130         }
1131         else {
1132                 return (BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, TRUE) != NULL);
1133         }
1134 }
1135
1136 static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg))
1137 {
1138         uiBlock *block;
1139         uiBut *but;
1140         uiLayout *layout, *split, *col;
1141         uiStyle *style= U.uistyles.first;
1142         struct RecentFile *recent;
1143         int i;
1144         MenuType *mt= WM_menutype_find("USERPREF_MT_splash", TRUE);
1145         char url[96];
1146         
1147 #ifdef NAN_BUILDINFO
1148         int ver_width, rev_width;
1149         char *version_str = NULL;
1150         char *revision_str = NULL;
1151         char version_buf[128];
1152         char revision_buf[128];
1153         extern char build_rev[];
1154         
1155         version_str = &version_buf[0];
1156         revision_str = &revision_buf[0];
1157         
1158         sprintf(version_str, "%d.%02d.%d", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION);
1159         sprintf(revision_str, "r%s", build_rev);
1160         
1161         BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.dpi);
1162         ver_width = (int)BLF_width(style->widgetlabel.uifont_id, version_str) + 5;
1163         rev_width = (int)BLF_width(style->widgetlabel.uifont_id, revision_str) + 5;
1164 #endif //NAN_BUILDINFO
1165
1166         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
1167         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
1168         
1169         but= uiDefBut(block, BUT_IMAGE, 0, "", 0, 10, 501, 282, NULL, 0.0, 0.0, 0, 0, "");
1170         uiButSetFunc(but, wm_block_splash_close, block, NULL);
1171         uiBlockSetFunc(block, wm_block_splash_refreshmenu, block, NULL);
1172         
1173 #ifdef NAN_BUILDINFO    
1174         uiDefBut(block, LABEL, 0, version_str, 494-ver_width, 282-24, ver_width, 20, NULL, 0, 0, 0, 0, NULL);
1175         uiDefBut(block, LABEL, 0, revision_str, 494-rev_width, 282-36, rev_width, 20, NULL, 0, 0, 0, 0, NULL);
1176 #endif //NAN_BUILDINFO
1177         
1178         layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, 480, 110, style);
1179         
1180         uiBlockSetEmboss(block, UI_EMBOSS);
1181         /* show the splash menu (containing interaction presets), using python */
1182         if (mt) {
1183                 Menu menu= {NULL};
1184                 menu.layout= layout;
1185                 menu.type= mt;
1186                 mt->draw(C, &menu);
1187
1188 //              wmWindowManager *wm= CTX_wm_manager(C);
1189 //              uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE);
1190         }
1191         
1192         uiBlockSetEmboss(block, UI_EMBOSSP);
1193         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
1194         
1195         split = uiLayoutSplit(layout, 0, 0);
1196         col = uiLayoutColumn(split, 0);
1197         uiItemL(col, "Links", ICON_NONE);
1198         uiItemStringO(col, "Donations", ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/blenderorg/blender-foundation/donation-payment/");
1199         uiItemStringO(col, "Release Log", ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/development/release-logs/blender-257/");
1200         uiItemStringO(col, "Manual", ICON_URL, "WM_OT_url_open", "url", "http://wiki.blender.org/index.php/Doc:Manual");
1201         uiItemStringO(col, "Blender Website", ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/");
1202         uiItemStringO(col, "User Community", ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/community/user-community/"); // 
1203         if(strcmp(STRINGIFY(BLENDER_VERSION_CYCLE), "release")==0) {
1204                 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d" STRINGIFY(BLENDER_VERSION_CHAR) "_release", BLENDER_VERSION/100, BLENDER_VERSION%100);
1205         }
1206         else {
1207                 BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d_%d", BLENDER_VERSION/100, BLENDER_VERSION%100, BLENDER_SUBVERSION);
1208         }
1209         uiItemStringO(col, "Python API Reference", ICON_URL, "WM_OT_url_open", "url", url);
1210         uiItemL(col, "", ICON_NONE);
1211
1212         col = uiLayoutColumn(split, 0);
1213
1214         if(wm_resource_check_prev()) {
1215                 uiItemO(col, NULL, ICON_NEW, "WM_OT_copy_prev_settings");
1216                 uiItemS(col);
1217         }
1218
1219         uiItemL(col, "Recent", ICON_NONE);
1220         for(recent = G.recent_files.first, i=0; (i<5) && (recent); recent = recent->next, i++) {
1221                 uiItemStringO(col, BLI_path_basename(recent->filepath), ICON_FILE_BLEND, "WM_OT_open_mainfile", "filepath", recent->filepath);
1222         }
1223
1224         uiItemS(col);
1225         uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session");
1226         uiItemL(col, "", ICON_NONE);
1227         
1228         uiCenteredBoundsBlock(block, 0);
1229         uiEndBlock(C, block);
1230         
1231         return block;
1232 }
1233
1234 static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1235 {
1236         uiPupBlock(C, wm_block_create_splash, NULL);
1237         
1238         return OPERATOR_FINISHED;
1239 }
1240
1241 static void WM_OT_splash(wmOperatorType *ot)
1242 {
1243         ot->name= "Splash Screen";
1244         ot->idname= "WM_OT_splash";
1245         ot->description= "Opens a blocking popup region with release info";
1246         
1247         ot->invoke= wm_splash_invoke;
1248         ot->poll= WM_operator_winactive;
1249 }
1250
1251
1252 /* ***************** Search menu ************************* */
1253 static void operator_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2)
1254 {
1255         wmOperatorType *ot= arg2;
1256         
1257         if(ot)
1258                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
1259 }
1260
1261 static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
1262 {
1263         wmOperatorType *ot = WM_operatortype_first();
1264         
1265         for(; ot; ot= ot->next) {
1266                 
1267                 if(BLI_strcasestr(ot->name, str)) {
1268                         if(WM_operator_poll((bContext*)C, ot)) {
1269                                 char name[256];
1270                                 int len= strlen(ot->name);
1271                                 
1272                                 /* display name for menu, can hold hotkey */
1273                                 BLI_strncpy(name, ot->name, 256);
1274                                 
1275                                 /* check for hotkey */
1276                                 if(len < 256-6) {
1277                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
1278                                                 name[len]= '|';
1279                                 }
1280                                 
1281                                 if(0==uiSearchItemAdd(items, name, ot, 0))
1282                                         break;
1283                         }
1284                 }
1285         }
1286 }
1287
1288 static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_op))
1289 {
1290         static char search[256]= "";
1291         wmEvent event;
1292         wmWindow *win= CTX_wm_window(C);
1293         uiBlock *block;
1294         uiBut *but;
1295         
1296         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
1297         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
1298         
1299         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, 0, 0, "");
1300         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
1301         
1302         /* fake button, it holds space for search items */
1303         uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxhHeight(), 180, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
1304         
1305         uiPopupBoundsBlock(block, 6, 0, -20); /* move it downwards, mouse over button */
1306         uiEndBlock(C, block);
1307         
1308         event= *(win->eventstate);      /* XXX huh huh? make api call */
1309         event.type= EVT_BUT_OPEN;
1310         event.val= KM_PRESS;
1311         event.customdata= but;
1312         event.customdatafree= FALSE;
1313         wm_event_add(win, &event);
1314         
1315         return block;
1316 }
1317
1318 static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
1319 {
1320         return OPERATOR_FINISHED;       
1321 }
1322
1323 static int wm_search_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1324 {
1325         uiPupBlock(C, wm_block_search_menu, op);
1326         
1327         return OPERATOR_CANCELLED;
1328 }
1329
1330 /* op->poll */
1331 static int wm_search_menu_poll(bContext *C)
1332 {
1333         if(CTX_wm_window(C)==NULL) return 0;
1334         if(CTX_wm_area(C) && CTX_wm_area(C)->spacetype==SPACE_CONSOLE) return 0;  // XXX - so we can use the shortcut in the console
1335         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
1336         if(CTX_data_edit_object(C) && CTX_data_edit_object(C)->type==OB_FONT) return 0; // XXX - so we can use the spacebar for entering text
1337         return 1;
1338 }
1339
1340 static void WM_OT_search_menu(wmOperatorType *ot)
1341 {
1342         ot->name= "Search Menu";
1343         ot->idname= "WM_OT_search_menu";
1344         
1345         ot->invoke= wm_search_menu_invoke;
1346         ot->exec= wm_search_menu_exec;
1347         ot->poll= wm_search_menu_poll;
1348 }
1349
1350 static int wm_call_menu_exec(bContext *C, wmOperator *op)
1351 {
1352         char idname[BKE_ST_MAXNAME];
1353         RNA_string_get(op->ptr, "name", idname);
1354
1355         uiPupMenuInvoke(C, idname);
1356
1357         return OPERATOR_CANCELLED;
1358 }
1359
1360 static void WM_OT_call_menu(wmOperatorType *ot)
1361 {
1362         ot->name= "Call Menu";
1363         ot->idname= "WM_OT_call_menu";
1364
1365         ot->exec= wm_call_menu_exec;
1366         ot->poll= WM_operator_winactive;
1367
1368         RNA_def_string(ot->srna, "name", "", BKE_ST_MAXNAME, "Name", "Name of the menu");
1369 }
1370
1371 /* ************ window / screen operator definitions ************** */
1372
1373 /* this poll functions is needed in place of WM_operator_winactive
1374  * while it crashes on full screen */
1375 static int wm_operator_winactive_normal(bContext *C)
1376 {
1377         wmWindow *win= CTX_wm_window(C);
1378
1379         if(win==NULL || win->screen==NULL || win->screen->full != SCREENNORMAL)
1380                 return 0;
1381
1382         return 1;
1383 }
1384
1385 static void WM_OT_window_duplicate(wmOperatorType *ot)
1386 {
1387         ot->name= "Duplicate Window";
1388         ot->idname= "WM_OT_window_duplicate";
1389         ot->description="Duplicate the current Blender window";
1390                 
1391         ot->exec= wm_window_duplicate_exec;
1392         ot->poll= wm_operator_winactive_normal;
1393 }
1394
1395 static void WM_OT_save_homefile(wmOperatorType *ot)
1396 {
1397         ot->name= "Save User Settings";
1398         ot->idname= "WM_OT_save_homefile";
1399         ot->description="Make the current file the default .blend file";
1400                 
1401         ot->invoke= WM_operator_confirm;
1402         ot->exec= WM_write_homefile;
1403         ot->poll= WM_operator_winactive;
1404 }
1405
1406 static void WM_OT_read_homefile(wmOperatorType *ot)
1407 {
1408         ot->name= "Reload Start-Up File";
1409         ot->idname= "WM_OT_read_homefile";
1410         ot->description="Open the default file (doesn't save the current file)";
1411         
1412         ot->invoke= WM_operator_confirm;
1413         ot->exec= WM_read_homefile_exec;
1414         /* ommit poll to run in background mode */
1415 }
1416
1417 static void WM_OT_read_factory_settings(wmOperatorType *ot)
1418 {
1419         ot->name= "Load Factory Settings";
1420         ot->idname= "WM_OT_read_factory_settings";
1421         ot->description="Load default file and user preferences";
1422         
1423         ot->invoke= WM_operator_confirm;
1424         ot->exec= WM_read_homefile_exec;
1425         /* ommit poll to run in background mode */
1426 }
1427
1428 /* *************** open file **************** */
1429
1430 static void open_set_load_ui(wmOperator *op)
1431 {
1432         if(!RNA_property_is_set(op->ptr, "load_ui"))
1433                 RNA_boolean_set(op->ptr, "load_ui", !(U.flag & USER_FILENOUI));
1434 }
1435
1436 static void open_set_use_scripts(wmOperator *op)
1437 {
1438         if(!RNA_property_is_set(op->ptr, "use_scripts")) {
1439                 /* use G_SCRIPT_AUTOEXEC rather then the userpref because this means if
1440                  * the flag has been disabled from the command line, then opening
1441                  * from the menu wont enable this setting. */
1442                 RNA_boolean_set(op->ptr, "use_scripts", (G.f & G_SCRIPT_AUTOEXEC));
1443         }
1444 }
1445
1446 static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1447 {
1448         const char *openname= G.main->name;
1449
1450         /* if possible, get the name of the most recently used .blend file */
1451         if (G.recent_files.first) {
1452                 struct RecentFile *recent = G.recent_files.first;
1453                 openname = recent->filepath;
1454         }
1455
1456         RNA_string_set(op->ptr, "filepath", openname);
1457         open_set_load_ui(op);
1458         open_set_use_scripts(op);
1459
1460         WM_event_add_fileselect(C, op);
1461
1462         return OPERATOR_RUNNING_MODAL;
1463 }
1464
1465 static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
1466 {
1467         char path[FILE_MAX];
1468
1469         RNA_string_get(op->ptr, "filepath", path);
1470         open_set_load_ui(op);
1471         open_set_use_scripts(op);
1472
1473         if(RNA_boolean_get(op->ptr, "load_ui"))
1474                 G.fileflags &= ~G_FILE_NO_UI;
1475         else
1476                 G.fileflags |= G_FILE_NO_UI;
1477                 
1478         if(RNA_boolean_get(op->ptr, "use_scripts"))
1479                 G.f |= G_SCRIPT_AUTOEXEC;
1480         else
1481                 G.f &= ~G_SCRIPT_AUTOEXEC;
1482         
1483         // XXX wm in context is not set correctly after WM_read_file -> crash
1484         // do it before for now, but is this correct with multiple windows?
1485         WM_event_add_notifier(C, NC_WINDOW, NULL);
1486
1487         WM_read_file(C, path, op->reports);
1488         
1489         return OPERATOR_FINISHED;
1490 }
1491
1492 static void WM_OT_open_mainfile(wmOperatorType *ot)
1493 {
1494         ot->name= "Open Blender File";
1495         ot->idname= "WM_OT_open_mainfile";
1496         ot->description="Open a Blender file";
1497         
1498         ot->invoke= wm_open_mainfile_invoke;
1499         ot->exec= wm_open_mainfile_exec;
1500         ot->poll= WM_operator_winactive;
1501         
1502         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH);
1503
1504         RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file");
1505         RNA_def_boolean(ot->srna, "use_scripts", 1, "Trusted Source", "Allow blend file execute scripts automatically, default available from system preferences");
1506 }
1507
1508 /* **************** link/append *************** */
1509
1510 static int wm_link_append_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1511 {
1512         if(!RNA_property_is_set(op->ptr, "relative_path"))
1513                 RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
1514
1515         if(RNA_property_is_set(op->ptr, "filepath")) {
1516                 return WM_operator_call(C, op);
1517         } 
1518         else {
1519                 /* XXX TODO solve where to get last linked library from */
1520                 RNA_string_set(op->ptr, "filepath", G.lib);
1521                 WM_event_add_fileselect(C, op);
1522                 return OPERATOR_RUNNING_MODAL;
1523         }
1524 }
1525
1526 static short wm_link_append_flag(wmOperator *op)
1527 {
1528         short flag= 0;
1529
1530         if(RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
1531         if(RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
1532         if(RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
1533         if(RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
1534         if(RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE;
1535
1536         return flag;
1537 }
1538
1539 static int wm_link_append_exec(bContext *C, wmOperator *op)
1540 {
1541         Main *bmain= CTX_data_main(C);
1542         Scene *scene= CTX_data_scene(C);
1543         Main *mainl= NULL;
1544         BlendHandle *bh;
1545         PropertyRNA *prop;
1546         char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[GROUP_MAX];
1547         int idcode, totfiles=0;
1548         short flag;
1549
1550         name[0] = '\0';
1551         RNA_string_get(op->ptr, "filename", name);
1552         RNA_string_get(op->ptr, "directory", dir);
1553
1554         /* test if we have a valid data */
1555         if(BLO_is_a_library(dir, libname, group) == 0) {
1556                 BKE_report(op->reports, RPT_ERROR, "Not a library");
1557                 return OPERATOR_CANCELLED;
1558         }
1559         else if(group[0] == 0) {
1560                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1561                 return OPERATOR_CANCELLED;
1562         }
1563         else if(BLI_path_cmp(bmain->name, libname) == 0) {
1564                 BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
1565                 return OPERATOR_CANCELLED;
1566         }
1567
1568         /* check if something is indicated for append/link */
1569         prop = RNA_struct_find_property(op->ptr, "files");
1570         if(prop) {
1571                 totfiles= RNA_property_collection_length(op->ptr, prop);
1572                 if(totfiles == 0) {
1573                         if(name[0] == '\0') {
1574                                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1575                                 return OPERATOR_CANCELLED;
1576                         }
1577                 }
1578         }
1579         else if(name[0] == '\0') {
1580                 BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
1581                 return OPERATOR_CANCELLED;
1582         }
1583
1584         bh = BLO_blendhandle_from_file(libname, op->reports);
1585
1586         if(bh == NULL) {
1587                 /* unlikely since we just browsed it, but possible
1588                  * error reports will have been made by BLO_blendhandle_from_file() */
1589                 return OPERATOR_CANCELLED;
1590         }
1591
1592
1593         /* from here down, no error returns */
1594
1595         idcode = BKE_idcode_from_name(group);
1596
1597         /* now we have or selected, or an indicated file */
1598         if(RNA_boolean_get(op->ptr, "autoselect"))
1599                 scene_deselect_all(scene);
1600
1601         
1602         flag = wm_link_append_flag(op);
1603
1604         /* sanity checks for flag */
1605         if(scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
1606                 /* TODO, user never gets this message */
1607                 BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name+2);
1608                 flag &= ~FILE_GROUP_INSTANCE;
1609         }
1610
1611
1612         /* tag everything, all untagged data can be made local
1613          * its also generally useful to know what is new
1614          *
1615          * take extra care flag_all_listbases_ids(LIB_LINK_TAG, 0) is called after! */
1616         flag_all_listbases_ids(LIB_PRE_EXISTING, 1);
1617
1618         /* here appending/linking starts */
1619         mainl = BLO_library_append_begin(C, &bh, libname);
1620         if(totfiles == 0) {
1621                 BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag);
1622         }
1623         else {
1624                 RNA_BEGIN(op->ptr, itemptr, "files") {
1625                         RNA_string_get(&itemptr, "name", name);
1626                         BLO_library_append_named_part(C, mainl, &bh, name, idcode, flag);
1627                 }
1628                 RNA_END;
1629         }
1630         BLO_library_append_end(C, mainl, &bh, idcode, flag);
1631         
1632         /* mark all library linked objects to be updated */
1633         recalc_all_library_objects(bmain);
1634
1635         /* append, rather than linking */
1636         if((flag & FILE_LINK)==0) {
1637                 Library *lib= BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
1638                 if(lib) all_local(lib, 1);
1639                 else    BLI_assert(!"cant find name of just added library!");
1640         }
1641
1642         /* important we unset, otherwise these object wont
1643          * link into other scenes from this blend file */
1644         flag_all_listbases_ids(LIB_PRE_EXISTING, 0);
1645
1646         /* recreate dependency graph to include new objects */
1647         DAG_scene_sort(bmain, scene);
1648         DAG_ids_flush_update(bmain, 0);
1649
1650         BLO_blendhandle_close(bh);
1651
1652         /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
1653         BLI_strncpy(G.lib, dir, FILE_MAX);
1654
1655         WM_event_add_notifier(C, NC_WINDOW, NULL);
1656
1657         return OPERATOR_FINISHED;
1658 }
1659
1660 static void WM_OT_link_append(wmOperatorType *ot)
1661 {
1662         ot->name= "Link/Append from Library";
1663         ot->idname= "WM_OT_link_append";
1664         ot->description= "Link or Append from a Library .blend file";
1665         
1666         ot->invoke= wm_link_append_invoke;
1667         ot->exec= wm_link_append_exec;
1668         ot->poll= WM_operator_winactive;
1669         
1670         ot->flag |= OPTYPE_UNDO;
1671
1672         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_DIRECTORY|WM_FILESEL_FILENAME| WM_FILESEL_RELPATH);
1673         
1674         RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending");
1675         RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects");
1676         RNA_def_boolean(ot->srna, "active_layer", 1, "Active Layer", "Put the linked objects on the active layer");
1677         RNA_def_boolean(ot->srna, "instance_groups", 1, "Instance Groups", "Create instances for each group as a DupliGroup");
1678
1679         RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
1680 }       
1681
1682 /* *************** recover last session **************** */
1683
1684 static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
1685 {
1686         char filename[FILE_MAX];
1687
1688         G.fileflags |= G_FILE_RECOVER;
1689
1690         // XXX wm in context is not set correctly after WM_read_file -> crash
1691         // do it before for now, but is this correct with multiple windows?
1692         WM_event_add_notifier(C, NC_WINDOW, NULL);
1693
1694         /* load file */
1695         BLI_make_file_string("/", filename, btempdir, "quit.blend");
1696         WM_read_file(C, filename, op->reports);
1697
1698         G.fileflags &= ~G_FILE_RECOVER;
1699         return OPERATOR_FINISHED;
1700 }
1701
1702 static void WM_OT_recover_last_session(wmOperatorType *ot)
1703 {
1704         ot->name= "Recover Last Session";
1705         ot->idname= "WM_OT_recover_last_session";
1706         ot->description="Open the last closed file (\"quit.blend\")";
1707         
1708         ot->exec= wm_recover_last_session_exec;
1709         ot->poll= WM_operator_winactive;
1710 }
1711
1712 /* *************** recover auto save **************** */
1713
1714 static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
1715 {
1716         char path[FILE_MAX];
1717
1718         RNA_string_get(op->ptr, "filepath", path);
1719
1720         G.fileflags |= G_FILE_RECOVER;
1721
1722         // XXX wm in context is not set correctly after WM_read_file -> crash
1723         // do it before for now, but is this correct with multiple windows?
1724         WM_event_add_notifier(C, NC_WINDOW, NULL);
1725
1726         /* load file */
1727         WM_read_file(C, path, op->reports);
1728
1729         G.fileflags &= ~G_FILE_RECOVER;
1730
1731         return OPERATOR_FINISHED;
1732 }
1733
1734 static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1735 {
1736         char filename[FILE_MAX];
1737
1738         wm_autosave_location(filename);
1739         RNA_string_set(op->ptr, "filepath", filename);
1740         WM_event_add_fileselect(C, op);
1741
1742         return OPERATOR_RUNNING_MODAL;
1743 }
1744
1745 static void WM_OT_recover_auto_save(wmOperatorType *ot)
1746 {
1747         ot->name= "Recover Auto Save";
1748         ot->idname= "WM_OT_recover_auto_save";
1749         ot->description="Open an automatically saved file to recover it";
1750         
1751         ot->exec= wm_recover_auto_save_exec;
1752         ot->invoke= wm_recover_auto_save_invoke;
1753         ot->poll= WM_operator_winactive;
1754
1755         WM_operator_properties_filesel(ot, BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH);
1756 }
1757
1758 /* *************** save file as **************** */
1759
1760 static void untitled(char *name)
1761 {
1762         if(G.save_over == 0 && strlen(name) < FILE_MAX-16) {
1763                 char *c= BLI_last_slash(name);
1764                 
1765                 if(c)
1766                         strcpy(&c[1], "untitled.blend");
1767                 else
1768                         strcpy(name, "untitled.blend");
1769         }
1770 }
1771
1772 static void save_set_compress(wmOperator *op)
1773 {
1774         if(!RNA_property_is_set(op->ptr, "compress")) {
1775                 if(G.save_over) /* keep flag for existing file */
1776                         RNA_boolean_set(op->ptr, "compress", G.fileflags & G_FILE_COMPRESS);
1777                 else /* use userdef for new file */
1778                         RNA_boolean_set(op->ptr, "compress", U.flag & USER_FILECOMPRESS);
1779         }
1780 }
1781
1782 static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1783 {
1784         char name[FILE_MAX];
1785
1786         save_set_compress(op);
1787         
1788         /* if not saved before, get the name of the most recently used .blend file */
1789         if(G.main->name[0]==0 && G.recent_files.first) {
1790                 struct RecentFile *recent = G.recent_files.first;
1791                 BLI_strncpy(name, recent->filepath, FILE_MAX);
1792         }
1793         else
1794                 BLI_strncpy(name, G.main->name, FILE_MAX);
1795         
1796         untitled(name);
1797         RNA_string_set(op->ptr, "filepath", name);
1798         
1799         WM_event_add_fileselect(C, op);
1800
1801         return OPERATOR_RUNNING_MODAL;
1802 }
1803
1804 /* function used for WM_OT_save_mainfile too */
1805 static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
1806 {
1807         char path[FILE_MAX];
1808         int fileflags;
1809         int copy=0;
1810
1811         save_set_compress(op);
1812         
1813         if(RNA_property_is_set(op->ptr, "filepath"))
1814                 RNA_string_get(op->ptr, "filepath", path);
1815         else {
1816                 BLI_strncpy(path, G.main->name, FILE_MAX);
1817                 untitled(path);
1818         }
1819
1820         if(RNA_property_is_set(op->ptr, "copy"))
1821                 copy = RNA_boolean_get(op->ptr, "copy");
1822         
1823         fileflags= G.fileflags;
1824
1825         /* set compression flag */
1826         if(RNA_boolean_get(op->ptr, "compress"))                fileflags |=  G_FILE_COMPRESS;
1827         else                                                                                    fileflags &= ~G_FILE_COMPRESS;
1828         if(RNA_boolean_get(op->ptr, "relative_remap"))  fileflags |=  G_FILE_RELATIVE_REMAP;
1829         else                                                                                    fileflags &= ~G_FILE_RELATIVE_REMAP;
1830
1831         if ( WM_write_file(C, path, fileflags, op->reports, copy) != 0)
1832                 return OPERATOR_CANCELLED;
1833
1834         WM_event_add_notifier(C, NC_WM|ND_FILESAVE, NULL);
1835
1836         return OPERATOR_FINISHED;
1837 }
1838
1839 /* function used for WM_OT_save_mainfile too */
1840 static int blend_save_check(bContext *UNUSED(C), wmOperator *op)
1841 {
1842         char filepath[FILE_MAX];
1843         RNA_string_get(op->ptr, "filepath", filepath);
1844         if(BLI_replace_extension(filepath, sizeof(filepath), ".blend")) {
1845                 RNA_string_set(op->ptr, "filepath", filepath);
1846                 return TRUE;
1847         }
1848         return FALSE;
1849 }
1850
1851 static void WM_OT_save_as_mainfile(wmOperatorType *ot)
1852 {
1853         ot->name= "Save As Blender File";
1854         ot->idname= "WM_OT_save_as_mainfile";
1855         ot->description="Save the current file in the desired location";
1856         
1857         ot->invoke= wm_save_as_mainfile_invoke;
1858         ot->exec= wm_save_as_mainfile_exec;
1859         ot->check= blend_save_check;
1860         /* ommit window poll so this can work in background mode */
1861
1862         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
1863         RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file");
1864         RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", "Remap relative paths when saving in a different directory");
1865         RNA_def_boolean(ot->srna, "copy", 0, "Save Copy", "Save a copy of the actual working state but does not make saved file active.");
1866 }
1867
1868 /* *************** save file directly ******** */
1869
1870 static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1871 {
1872         char name[FILE_MAX];
1873         int check_existing=1;
1874         
1875         /* cancel if no active window */
1876         if (CTX_wm_window(C) == NULL)
1877                 return OPERATOR_CANCELLED;
1878
1879         save_set_compress(op);
1880
1881         /* if not saved before, get the name of the most recently used .blend file */
1882         if(G.main->name[0]==0 && G.recent_files.first) {
1883                 struct RecentFile *recent = G.recent_files.first;
1884                 BLI_strncpy(name, recent->filepath, FILE_MAX);
1885         }
1886         else
1887                 BLI_strncpy(name, G.main->name, FILE_MAX);
1888
1889         untitled(name);
1890         
1891         RNA_string_set(op->ptr, "filepath", name);
1892         
1893         if (RNA_struct_find_property(op->ptr, "check_existing"))
1894                 if (RNA_boolean_get(op->ptr, "check_existing")==0)
1895                         check_existing = 0;
1896         
1897         if (G.save_over) {
1898                 if (check_existing)
1899                         uiPupMenuSaveOver(C, op, name);
1900                 else {
1901                         wm_save_as_mainfile_exec(C, op);
1902                 }
1903         } else {
1904                 WM_event_add_fileselect(C, op);
1905         }
1906         
1907         return OPERATOR_RUNNING_MODAL;
1908 }
1909
1910 static void WM_OT_save_mainfile(wmOperatorType *ot)
1911 {
1912         ot->name= "Save Blender File";
1913         ot->idname= "WM_OT_save_mainfile";
1914         ot->description="Save the current Blender file";
1915         
1916         ot->invoke= wm_save_mainfile_invoke;
1917         ot->exec= wm_save_as_mainfile_exec;
1918         ot->check= blend_save_check;
1919         ot->poll= NULL;
1920         
1921         WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
1922         RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file");
1923         RNA_def_boolean(ot->srna, "relative_remap", 0, "Remap Relative", "Remap relative paths when saving in a different directory");
1924 }
1925
1926 /* XXX: move these collada operators to a more appropriate place */
1927 #ifdef WITH_COLLADA
1928
1929 #include "../../collada/collada.h"
1930
1931 static int wm_collada_export_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1932 {       
1933         if(!RNA_property_is_set(op->ptr, "filepath")) {
1934                 char filepath[FILE_MAX];
1935                 BLI_strncpy(filepath, G.main->name, sizeof(filepath));
1936                 BLI_replace_extension(filepath, sizeof(filepath), ".dae");
1937                 RNA_string_set(op->ptr, "filepath", filepath);
1938         }
1939
1940         WM_event_add_fileselect(C, op);
1941
1942         return OPERATOR_RUNNING_MODAL;
1943 }
1944
1945 /* function used for WM_OT_save_mainfile too */
1946 static int wm_collada_export_exec(bContext *C, wmOperator *op)
1947 {
1948         char filename[FILE_MAX];
1949         
1950         if(!RNA_property_is_set(op->ptr, "filepath")) {
1951                 BKE_report(op->reports, RPT_ERROR, "No filename given");
1952                 return OPERATOR_CANCELLED;
1953         }
1954
1955         RNA_string_get(op->ptr, "filepath", filename);
1956         if(collada_export(CTX_data_scene(C), filename)) {
1957                 return OPERATOR_FINISHED;
1958         }
1959         else {
1960                 return OPERATOR_CANCELLED;
1961         }
1962 }
1963
1964 static void WM_OT_collada_export(wmOperatorType *ot)
1965 {
1966         ot->name= "Export COLLADA";
1967         ot->idname= "WM_OT_collada_export";
1968         
1969         ot->invoke= wm_collada_export_invoke;
1970         ot->exec= wm_collada_export_exec;
1971         ot->poll= WM_operator_winactive;
1972         
1973         WM_operator_properties_filesel(ot, FOLDERFILE|COLLADAFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
1974 }
1975
1976 /* function used for WM_OT_save_mainfile too */
1977 static int wm_collada_import_exec(bContext *C, wmOperator *op)
1978 {
1979         char filename[FILE_MAX];
1980         
1981         if(!RNA_property_is_set(op->ptr, "filepath")) {
1982                 BKE_report(op->reports, RPT_ERROR, "No filename given");
1983                 return OPERATOR_CANCELLED;
1984         }
1985
1986         RNA_string_get(op->ptr, "filepath", filename);
1987         collada_import(C, filename);
1988         
1989         return OPERATOR_FINISHED;
1990 }
1991
1992 static void WM_OT_collada_import(wmOperatorType *ot)
1993 {
1994         ot->name= "Import COLLADA";
1995         ot->idname= "WM_OT_collada_import";
1996         
1997         ot->invoke= WM_operator_filesel;
1998         ot->exec= wm_collada_import_exec;
1999         ot->poll= WM_operator_winactive;
2000         
2001         WM_operator_properties_filesel(ot, FOLDERFILE|COLLADAFILE, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH);
2002 }
2003
2004 #endif
2005
2006
2007 /* *********************** */
2008
2009 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
2010 {
2011         ot->name= "Toggle Fullscreen";
2012         ot->idname= "WM_OT_window_fullscreen_toggle";
2013         ot->description="Toggle the current window fullscreen";
2014
2015         ot->exec= wm_window_fullscreen_toggle_exec;
2016         ot->poll= WM_operator_winactive;
2017 }
2018
2019 static int wm_exit_blender_op(bContext *C, wmOperator *op)
2020 {
2021         WM_operator_free(op);
2022         
2023         WM_exit(C);     
2024         
2025         return OPERATOR_FINISHED;
2026 }
2027
2028 static void WM_OT_quit_blender(wmOperatorType *ot)
2029 {
2030         ot->name= "Quit Blender";
2031         ot->idname= "WM_OT_quit_blender";
2032         ot->description= "Quit Blender";
2033
2034         ot->invoke= WM_operator_confirm;
2035         ot->exec= wm_exit_blender_op;
2036         ot->poll= WM_operator_winactive;
2037 }
2038
2039 /* *********************** */
2040
2041 static int wm_console_toggle_op(bContext *UNUSED(C), wmOperator *UNUSED(op))
2042 {
2043         GHOST_toggleConsole(2);
2044         return OPERATOR_FINISHED;
2045 }
2046
2047 static void WM_OT_console_toggle(wmOperatorType *ot)
2048 {
2049         ot->name= "Toggle System Console";
2050         ot->idname= "WM_OT_console_toggle";
2051         ot->description= "Toggle System Console";
2052         
2053         ot->exec= wm_console_toggle_op;
2054         ot->poll= WM_operator_winactive;
2055 }
2056
2057 /* ************ default paint cursors, draw always around cursor *********** */
2058 /*
2059  - returns handler to free 
2060  - poll(bContext): returns 1 if draw should happen
2061  - draw(bContext): drawing callback for paint cursor
2062 */
2063
2064 void *WM_paint_cursor_activate(wmWindowManager *wm, int (*poll)(bContext *C),
2065                                    wmPaintCursorDraw draw, void *customdata)
2066 {
2067         wmPaintCursor *pc= MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
2068         
2069         BLI_addtail(&wm->paintcursors, pc);
2070         
2071         pc->customdata = customdata;
2072         pc->poll= poll;
2073         pc->draw= draw;
2074         
2075         return pc;
2076 }
2077
2078 void WM_paint_cursor_end(wmWindowManager *wm, void *handle)
2079 {
2080         wmPaintCursor *pc;
2081         
2082         for(pc= wm->paintcursors.first; pc; pc= pc->next) {
2083                 if(pc == (wmPaintCursor *)handle) {
2084                         BLI_remlink(&wm->paintcursors, pc);
2085                         MEM_freeN(pc);
2086                         return;
2087                 }
2088         }
2089 }
2090
2091 /* ************ window gesture operator-callback definitions ************** */
2092 /*
2093  * These are default callbacks for use in operators requiring gesture input
2094  */
2095
2096 /* **************** Border gesture *************** */
2097
2098 /* Border gesture has two types:
2099    1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border 
2100    2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends
2101
2102    It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type)
2103 */
2104
2105 static int border_apply_rect(wmOperator *op)
2106 {
2107         wmGesture *gesture= op->customdata;
2108         rcti *rect= gesture->customdata;
2109         
2110         if(rect->xmin==rect->xmax || rect->ymin==rect->ymax)
2111                 return 0;
2112
2113         
2114         /* operator arguments and storage. */
2115         RNA_int_set(op->ptr, "xmin", MIN2(rect->xmin, rect->xmax) );
2116         RNA_int_set(op->ptr, "ymin", MIN2(rect->ymin, rect->ymax) );
2117         RNA_int_set(op->ptr, "xmax", MAX2(rect->xmin, rect->xmax) );
2118         RNA_int_set(op->ptr, "ymax", MAX2(rect->ymin, rect->ymax) );
2119
2120         return 1;
2121 }
2122
2123 static int border_apply(bContext *C, wmOperator *op, int gesture_mode)
2124 {
2125         if (!border_apply_rect(op))
2126                 return 0;
2127         
2128         /* XXX weak; border should be configured for this without reading event types */
2129         if( RNA_struct_find_property(op->ptr, "gesture_mode") )
2130                 RNA_int_set(op->ptr, "gesture_mode", gesture_mode);
2131
2132         op->type->exec(C, op);
2133         return 1;
2134 }
2135
2136 static void wm_gesture_end(bContext *C, wmOperator *op)
2137 {
2138         wmGesture *gesture= op->customdata;
2139         
2140         WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
2141         op->customdata= NULL;
2142
2143         ED_area_tag_redraw(CTX_wm_area(C));
2144         
2145         if( RNA_struct_find_property(op->ptr, "cursor") )
2146                 WM_cursor_restore(CTX_wm_window(C));
2147 }
2148
2149 int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
2150 {
2151         if(ISTWEAK(event->type))
2152                 op->customdata= WM_gesture_new(C, event, WM_GESTURE_RECT);
2153         else
2154                 op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT);
2155
2156         /* add modal handler */
2157         WM_event_add_modal_handler(C, op);
2158         
2159         wm_gesture_tag_redraw(C);
2160
2161         return OPERATOR_RUNNING_MODAL;
2162 }
2163
2164 int WM_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
2165 {
2166         wmGesture *gesture= op->customdata;
2167         rcti *rect= gesture->customdata;
2168         int sx, sy;
2169         
2170         if(event->type== MOUSEMOVE) {
2171                 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
2172
2173                 if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
2174                         rect->xmin= rect->xmax= event->x - sx;
2175                         rect->ymin= rect->ymax= event->y - sy;
2176                 }
2177                 else {
2178                         rect->xmax= event->x - sx;
2179                         rect->ymax= event->y - sy;
2180                 }
2181                 border_apply_rect(op);
2182
2183                 wm_gesture_tag_redraw(C);
2184         }
2185         else if (event->type==EVT_MODAL_MAP) {
2186                 switch (event->val) {
2187                 case GESTURE_MODAL_BEGIN:
2188                         if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
2189                                 gesture->mode= 1;
2190                                 wm_gesture_tag_redraw(C);
2191                         }
2192                         break;
2193                 case GESTURE_MODAL_SELECT:
2194                 case GESTURE_MODAL_DESELECT:
2195                 case GESTURE_MODAL_IN:
2196                 case GESTURE_MODAL_OUT:
2197                         if(border_apply(C, op, event->val)) {
2198                                 wm_gesture_end(C, op);
2199                                 return OPERATOR_FINISHED;
2200                         }
2201                         wm_gesture_end(C, op);
2202                         return OPERATOR_CANCELLED;
2203                         break;
2204
2205                 case GESTURE_MODAL_CANCEL:
2206                         wm_gesture_end(C, op);
2207                         return OPERATOR_CANCELLED;
2208                 }
2209
2210         }
2211 //      // Allow view navigation???
2212 //      else {
2213 //              return OPERATOR_PASS_THROUGH;
2214 //      }
2215
2216         return OPERATOR_RUNNING_MODAL;
2217 }
2218
2219 /* **************** circle gesture *************** */
2220 /* works now only for selection or modal paint stuff, calls exec while hold mouse, exit on release */
2221
2222 #ifdef GESTURE_MEMORY
2223 int circle_select_size= 25; // XXX - need some operator memory thing\!
2224 #endif
2225
2226 int WM_gesture_circle_invoke(bContext *C, wmOperator *op, wmEvent *event)
2227 {
2228         op->customdata= WM_gesture_new(C, event, WM_GESTURE_CIRCLE);
2229         
2230         /* add modal handler */
2231         WM_event_add_modal_handler(C, op);
2232         
2233         wm_gesture_tag_redraw(C);
2234         
2235         return OPERATOR_RUNNING_MODAL;
2236 }
2237
2238 static void gesture_circle_apply(bContext *C, wmOperator *op)
2239 {
2240         wmGesture *gesture= op->customdata;
2241         rcti *rect= gesture->customdata;
2242         
2243         if(RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_NOP)
2244                 return;
2245
2246         /* operator arguments and storage. */
2247         RNA_int_set(op->ptr, "x", rect->xmin);
2248         RNA_int_set(op->ptr, "y", rect->ymin);
2249         RNA_int_set(op->ptr, "radius", rect->xmax);
2250         
2251         if(op->type->exec)
2252                 op->type->exec(C, op);
2253
2254 #ifdef GESTURE_MEMORY
2255         circle_select_size= rect->xmax;
2256 #endif
2257 }
2258
2259 int WM_gesture_circle_modal(bContext *C, wmOperator *op, wmEvent *event)
2260 {
2261         wmGesture *gesture= op->customdata;
2262         rcti *rect= gesture->customdata;
2263         int sx, sy;
2264
2265         if(event->type== MOUSEMOVE) {
2266                 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
2267
2268                 rect->xmin= event->x - sx;
2269                 rect->ymin= event->y - sy;
2270
2271                 wm_gesture_tag_redraw(C);
2272
2273                 if(gesture->mode)
2274                         gesture_circle_apply(C, op);
2275         }
2276         else if (event->type==EVT_MODAL_MAP) {
2277                 switch (event->val) {
2278                 case GESTURE_MODAL_CIRCLE_ADD:
2279                         rect->xmax += 2 + rect->xmax/10;
2280                         wm_gesture_tag_redraw(C);
2281                         break;
2282                 case GESTURE_MODAL_CIRCLE_SUB:
2283                         rect->xmax -= 2 + rect->xmax/10;
2284                         if(rect->xmax < 1) rect->xmax= 1;
2285                         wm_gesture_tag_redraw(C);
2286                         break;
2287                 case GESTURE_MODAL_SELECT:
2288                 case GESTURE_MODAL_DESELECT:
2289                 case GESTURE_MODAL_NOP:
2290                         if(RNA_struct_find_property(op->ptr, "gesture_mode"))
2291                                 RNA_int_set(op->ptr, "gesture_mode", event->val);
2292
2293                         if(event->val != GESTURE_MODAL_NOP) {
2294                                 /* apply first click */
2295                                 gesture_circle_apply(C, op);
2296                                 gesture->mode= 1;
2297                                 wm_gesture_tag_redraw(C);
2298                         }
2299                         break;
2300
2301                 case GESTURE_MODAL_CANCEL:
2302                 case GESTURE_MODAL_CONFIRM:
2303                         wm_gesture_end(C, op);
2304                         return OPERATOR_FINISHED; /* use finish or we dont get an undo */
2305                 }
2306         }
2307 //      // Allow view navigation???
2308 //      else {
2309 //              return OPERATOR_PASS_THROUGH;
2310 //      }
2311
2312         return OPERATOR_RUNNING_MODAL;
2313 }
2314
2315 #if 0
2316 /* template to copy from */
2317 void WM_OT_circle_gesture(wmOperatorType *ot)
2318 {
2319         ot->name= "Circle Gesture";
2320         ot->idname= "WM_OT_circle_gesture";
2321         ot->description="Enter rotate mode with a circular gesture";
2322         
2323         ot->invoke= WM_gesture_circle_invoke;
2324         ot->modal= WM_gesture_circle_modal;
2325         
2326         ot->poll= WM_operator_winactive;
2327         
2328         RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
2329         RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
2330         RNA_def_property(ot->srna, "radius", PROP_INT, PROP_NONE);
2331
2332 }
2333 #endif
2334
2335 /* **************** Tweak gesture *************** */
2336
2337 static void tweak_gesture_modal(bContext *C, wmEvent *event)
2338 {
2339         wmWindow *window= CTX_wm_window(C);
2340         wmGesture *gesture= window->tweak;
2341         rcti *rect= gesture->customdata;
2342         int sx, sy, val;
2343         
2344         switch(event->type) {
2345                 case MOUSEMOVE:
2346                 case INBETWEEN_MOUSEMOVE:
2347                         
2348                         wm_subwindow_getorigin(window, gesture->swinid, &sx, &sy);
2349                         
2350                         rect->xmax= event->x - sx;
2351                         rect->ymax= event->y - sy;
2352                         
2353                         if((val= wm_gesture_evaluate(gesture))) {
2354                                 wmEvent tevent;
2355
2356                                 tevent= *(window->eventstate);
2357                                 if(gesture->event_type==LEFTMOUSE)
2358                                         tevent.type= EVT_TWEAK_L;
2359                                 else if(gesture->event_type==RIGHTMOUSE)
2360                                         tevent.type= EVT_TWEAK_R;
2361                                 else
2362                                         tevent.type= EVT_TWEAK_M;
2363                                 tevent.val= val;
2364                                 /* mouse coords! */
2365                                 wm_event_add(window, &tevent);
2366                                 
2367                                 WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
2368                         }
2369                         
2370                         break;
2371                         
2372                 case LEFTMOUSE:
2373                 case RIGHTMOUSE:
2374                 case MIDDLEMOUSE:
2375                         if(gesture->event_type==event->type) {
2376                                 WM_gesture_end(C, gesture);
2377
2378                                 /* when tweak fails we should give the other keymap entries a chance */
2379                                 event->val= KM_RELEASE;
2380                         }
2381                         break;
2382                 default:
2383                         if(!ISTIMER(event->type)) {
2384                                 WM_gesture_end(C, gesture);
2385                         }
2386                         break;
2387         }
2388 }
2389
2390 /* standard tweak, called after window handlers passed on event */
2391 void wm_tweakevent_test(bContext *C, wmEvent *event, int action)
2392 {
2393         wmWindow *win= CTX_wm_window(C);
2394         
2395         if(win->tweak==NULL) {
2396                 if(CTX_wm_region(C)) {
2397                         if(event->val==KM_PRESS) { 
2398                                 if( ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) )
2399                                         win->tweak= WM_gesture_new(C, event, WM_GESTURE_TWEAK);
2400                         }
2401                 }
2402         }
2403         else {
2404                 /* no tweaks if event was handled */
2405                 if((action & WM_HANDLER_BREAK)) {
2406                         WM_gesture_end(C, win->tweak);
2407                 }
2408                 else
2409                         tweak_gesture_modal(C, event);
2410         }
2411 }
2412
2413 /* *********************** lasso gesture ****************** */
2414
2415 int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, wmEvent *event)
2416 {
2417         op->customdata= WM_gesture_new(C, event, WM_GESTURE_LASSO);
2418         
2419         /* add modal handler */
2420         WM_event_add_modal_handler(C, op);
2421         
2422         wm_gesture_tag_redraw(C);
2423         
2424         if( RNA_struct_find_property(op->ptr, "cursor") )
2425                 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor"));
2426         
2427         return OPERATOR_RUNNING_MODAL;
2428 }
2429
2430 int WM_gesture_lines_invoke(bContext *C, wmOperator *op, wmEvent *event)
2431 {
2432         op->customdata= WM_gesture_new(C, event, WM_GESTURE_LINES);
2433         
2434         /* add modal handler */
2435         WM_event_add_modal_handler(C, op);
2436         
2437         wm_gesture_tag_redraw(C);
2438         
2439         if( RNA_struct_find_property(op->ptr, "cursor") )
2440                 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor"));
2441         
2442         return OPERATOR_RUNNING_MODAL;
2443 }
2444
2445
2446 static void gesture_lasso_apply(bContext *C, wmOperator *op)
2447 {
2448         wmGesture *gesture= op->customdata;
2449         PointerRNA itemptr;
2450         float loc[2];
2451         int i;
2452         short *lasso= gesture->customdata;
2453         
2454         /* operator storage as path. */
2455
2456         for(i=0; i<gesture->points; i++, lasso+=2) {
2457                 loc[0]= lasso[0];
2458                 loc[1]= lasso[1];
2459                 RNA_collection_add(op->ptr, "path", &itemptr);
2460                 RNA_float_set_array(&itemptr, "loc", loc);
2461         }
2462         
2463         wm_gesture_end(C, op);
2464                 
2465         if(op->type->exec)
2466                 op->type->exec(C, op);
2467         
2468 }
2469
2470 int WM_gesture_lasso_modal(bContext *C, wmOperator *op, wmEvent *event)
2471 {
2472         wmGesture *gesture= op->customdata;
2473         int sx, sy;
2474         
2475         switch(event->type) {
2476                 case MOUSEMOVE:
2477                 case INBETWEEN_MOUSEMOVE:
2478                         
2479                         wm_gesture_tag_redraw(C);
2480                         
2481                         wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
2482
2483                         if(gesture->points == gesture->size) {
2484                                 short *old_lasso = gesture->customdata;
2485                                 gesture->customdata= MEM_callocN(2*sizeof(short)*(gesture->size + WM_LASSO_MIN_POINTS), "lasso points");
2486                                 memcpy(gesture->customdata, old_lasso, 2*sizeof(short)*gesture->size);
2487                                 gesture->size = gesture->size + WM_LASSO_MIN_POINTS;
2488                                 MEM_freeN(old_lasso);
2489                                 printf("realloc\n");
2490                         }
2491
2492                         {
2493                                 short x, y;
2494                                 short *lasso= gesture->customdata;
2495                                 
2496                                 lasso += (2 * gesture->points - 2);
2497                                 x = (event->x - sx - lasso[0]);
2498                                 y = (event->y - sy - lasso[1]);
2499                                 
2500                                 /* make a simple distance check to get a smoother lasso
2501                                    add only when at least 2 pixels between this and previous location */
2502                                 if((x*x+y*y) > 4) {
2503                                         lasso += 2;
2504                                         lasso[0] = event->x - sx;
2505                                         lasso[1] = event->y - sy;
2506                                         gesture->points++;
2507                                 }
2508                         }
2509                         break;
2510                         
2511                 case LEFTMOUSE:
2512                 case MIDDLEMOUSE:
2513                 case RIGHTMOUSE:
2514                         if(event->val==KM_RELEASE) {    /* key release */
2515                                 gesture_lasso_apply(C, op);
2516                                 return OPERATOR_FINISHED;
2517                         }
2518                         break;
2519                 case ESCKEY:
2520                         wm_gesture_end(C, op);
2521                         return OPERATOR_CANCELLED;
2522         }
2523         return OPERATOR_RUNNING_MODAL;
2524 }
2525
2526 int WM_gesture_lines_modal(bContext *C, wmOperator *op, wmEvent *event)
2527 {
2528         return WM_gesture_lasso_modal(C, op, event);
2529 }
2530
2531 #if 0
2532 /* template to copy from */
2533
2534 static int gesture_lasso_exec(bContext *C, wmOperator *op)
2535 {
2536         RNA_BEGIN(op->ptr, itemptr, "path") {
2537                 float loc[2];
2538                 
2539                 RNA_float_get_array(&itemptr, "loc", loc);
2540                 printf("Location: %f %f\n", loc[0], loc[1]);
2541         }
2542         RNA_END;
2543         
2544         return OPERATOR_FINISHED;
2545 }
2546
2547 void WM_OT_lasso_gesture(wmOperatorType *ot)
2548 {
2549         PropertyRNA *prop;
2550         
2551         ot->name= "Lasso Gesture";
2552         ot->idname= "WM_OT_lasso_gesture";
2553         ot->description="Select objects within the lasso as you move the pointer";
2554         
2555         ot->invoke= WM_gesture_lasso_invoke;
2556         ot->modal= WM_gesture_lasso_modal;
2557         ot->exec= gesture_lasso_exec;
2558         
2559         ot->poll= WM_operator_winactive;
2560         
2561         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
2562         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
2563 }
2564 #endif
2565
2566 /* *********************** straight line gesture ****************** */
2567
2568 static int straightline_apply(bContext *C, wmOperator *op)
2569 {
2570         wmGesture *gesture= op->customdata;
2571         rcti *rect= gesture->customdata;
2572         
2573         if(rect->xmin==rect->xmax && rect->ymin==rect->ymax)
2574                 return 0;
2575         
2576         /* operator arguments and storage. */
2577         RNA_int_set(op->ptr, "xstart", rect->xmin);
2578         RNA_int_set(op->ptr, "ystart", rect->ymin);
2579         RNA_int_set(op->ptr, "xend", rect->xmax);
2580         RNA_int_set(op->ptr, "yend", rect->ymax);
2581
2582         if(op->type->exec)
2583                 op->type->exec(C, op);
2584         
2585         return 1;
2586 }
2587
2588
2589 int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, wmEvent *event)
2590 {
2591         op->customdata= WM_gesture_new(C, event, WM_GESTURE_STRAIGHTLINE);
2592         
2593         /* add modal handler */
2594         WM_event_add_modal_handler(C, op);
2595         
2596         wm_gesture_tag_redraw(C);
2597         
2598         if( RNA_struct_find_property(op->ptr, "cursor") )
2599                 WM_cursor_modal(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor"));
2600                 
2601         return OPERATOR_RUNNING_MODAL;
2602 }
2603
2604 int WM_gesture_straightline_modal(bContext *C, wmOperator *op, wmEvent *event)
2605 {
2606         wmGesture *gesture= op->customdata;
2607         rcti *rect= gesture->customdata;
2608         int sx, sy;
2609         
2610         if(event->type== MOUSEMOVE) {
2611                 wm_subwindow_getorigin(CTX_wm_window(C), gesture->swinid, &sx, &sy);
2612                 
2613                 if(gesture->mode==0) {
2614                         rect->xmin= rect->xmax= event->x - sx;
2615                         rect->ymin= rect->ymax= event->y - sy;
2616                 }
2617                 else {
2618                         rect->xmax= event->x - sx;
2619                         rect->ymax= event->y - sy;
2620                         straightline_apply(C, op);
2621                 }
2622                 
2623                 wm_gesture_tag_redraw(C);
2624         }
2625         else if (event->type==EVT_MODAL_MAP) {
2626                 switch (event->val) {
2627                         case GESTURE_MODAL_BEGIN:
2628                                 if(gesture->mode==0) {
2629                                         gesture->mode= 1;
2630                                         wm_gesture_tag_redraw(C);
2631                                 }
2632                                 break;
2633                         case GESTURE_MODAL_SELECT:
2634                                 if(straightline_apply(C, op)) {
2635                                         wm_gesture_end(C, op);
2636                                         return OPERATOR_FINISHED;
2637                                 }
2638                                 wm_gesture_end(C, op);
2639                                 return OPERATOR_CANCELLED;
2640                                 break;
2641                                 
2642                         case GESTURE_MODAL_CANCEL:
2643                                 wm_gesture_end(C, op);
2644                                 return OPERATOR_CANCELLED;
2645                 }
2646                 
2647         }
2648
2649         return OPERATOR_RUNNING_MODAL;
2650 }
2651
2652 #if 0
2653 /* template to copy from */
2654 void WM_OT_straightline_gesture(wmOperatorType *ot)
2655 {
2656         PropertyRNA *prop;
2657         
2658         ot->name= "Straight Line Gesture";
2659         ot->idname= "WM_OT_straightline_gesture";
2660         ot->description="Draw a straight line as you move the pointer";
2661         
2662         ot->invoke= WM_gesture_straightline_invoke;
2663         ot->modal= WM_gesture_straightline_modal;
2664         ot->exec= gesture_straightline_exec;
2665         
2666         ot->poll= WM_operator_winactive;
2667         
2668         WM_operator_properties_gesture_straightline(ot, 0);
2669 }
2670 #endif
2671
2672 /* *********************** radial control ****************** */
2673
2674 static const int WM_RADIAL_CONTROL_DISPLAY_SIZE = 200;
2675
2676 typedef struct wmRadialControl {
2677         int mode;
2678         float initial_value, value, max_value;
2679         float col[4], tex_col[4];
2680         int initial_mouse[2];
2681         void *cursor;
2682         GLuint tex;
2683 } wmRadialControl;
2684
2685 static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
2686 {
2687         wmRadialControl *rc = (wmRadialControl*)customdata;
2688         ARegion *ar = CTX_wm_region(C);
2689         float r1=0.0f, r2=0.0f, r3=0.0f, angle=0.0f;
2690
2691         // int hit = 0;
2692         
2693         if(rc->mode == WM_RADIALCONTROL_STRENGTH)
2694                 rc->tex_col[3]= (rc->value + 0.5f);
2695
2696         if(rc->mode == WM_RADIALCONTROL_SIZE) {
2697                 r1= rc->value;
2698                 r2= rc->initial_value;
2699                 r3= r1;
2700         } else if(rc->mode == WM_RADIALCONTROL_STRENGTH) {
2701                 r1= (1 - rc->value) * WM_RADIAL_CONTROL_DISPLAY_SIZE;
2702                 r2= r3= (float)WM_RADIAL_CONTROL_DISPLAY_SIZE;
2703         } else if(rc->mode == WM_RADIALCONTROL_ANGLE) {
2704                 r1= r2= r3= (float)WM_RADIAL_CONTROL_DISPLAY_SIZE;
2705                 angle = rc->value;
2706         }
2707
2708         /* Keep cursor in the original place */
2709         x = rc->initial_mouse[0] - ar->winrct.xmin;
2710         y = rc->initial_mouse[1] - ar->winrct.ymin;
2711
2712         glTranslatef((float)x, (float)y, 0.0f);
2713
2714         glEnable(GL_BLEND);
2715
2716         if(rc->mode == WM_RADIALCONTROL_ANGLE) {
2717                 glRotatef(angle, 0, 0, 1);
2718         }
2719
2720         if (rc->tex) {
2721                 glBindTexture(GL_TEXTURE_2D, rc->tex);
2722
2723                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2724                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2725
2726                 glEnable(GL_TEXTURE_2D);
2727                 glBegin(GL_QUADS);
2728                 glColor4f(rc->tex_col[0], rc->tex_col[1], rc->tex_col[2], rc->tex_col[3]);
2729                 glTexCoord2f(0,0);
2730                 glVertex2f(-r3, -r3);
2731                 glTexCoord2f(1,0);
2732                 glVertex2f(r3, -r3);
2733                 glTexCoord2f(1,1);
2734                 glVertex2f(r3, r3);
2735                 glTexCoord2f(0,1);
2736                 glVertex2f(-r3, r3);
2737                 glEnd();
2738                 glDisable(GL_TEXTURE_2D);
2739         }
2740
2741         if(rc->mode == WM_RADIALCONTROL_ANGLE) {
2742                 glColor4f(rc->col[0], rc->col[1], rc->col[2], rc->col[3]);
2743                 glEnable(GL_LINE_SMOOTH);
2744                 glRotatef(-angle, 0, 0, 1);
2745                 fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
2746                 glRotatef(angle, 0, 0, 1);
2747                 fdrawline(0.0f, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
2748                 glDisable(GL_LINE_SMOOTH);
2749         }
2750
2751         glColor4f(rc->col[0], rc->col[1], rc->col[2], rc->col[3]);
2752         glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r1, 40);
2753         glutil_draw_lined_arc(0.0, (float)(M_PI*2.0), r2, 40);
2754         glDisable(GL_BLEND);
2755 }
2756
2757 int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2758 {
2759         wmRadialControl *rc = (wmRadialControl*)op->customdata;
2760         int mode, initial_mouse[2], delta[2];
2761         float dist;
2762         double new_value = RNA_float_get(op->ptr, "new_value");
2763         int ret = OPERATOR_RUNNING_MODAL;
2764         // float initial_value = RNA_float_get(op->ptr, "initial_value");
2765
2766         mode = RNA_enum_get(op->ptr, "mode");
2767         RNA_int_get_array(op->ptr, "initial_mouse", initial_mouse);
2768
2769         switch(event->type) {
2770         case MOUSEMOVE:
2771                 delta[0]= initial_mouse[0] - event->x;
2772                 delta[1]= initial_mouse[1] - event->y;
2773
2774                 //if (mode == WM_RADIALCONTROL_SIZE) 
2775                 //      delta[0]+= initial_value;
2776                 //else if(mode == WM_RADIALCONTROL_STRENGTH)
2777                 //      delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - initial_value);
2778                 //else if(mode == WM_RADIALCONTROL_ANGLE) {
2779                 //      delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value*M_PI/180.0f);
2780                 //      delta[1]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value*M_PI/180.0f);
2781                 //}
2782
2783                 dist= sqrtf(delta[0]*delta[0]+delta[1]*delta[1]);
2784
2785                 if(mode == WM_RADIALCONTROL_SIZE)
2786                         new_value = dist;
2787                 else if(mode == WM_RADIALCONTROL_STRENGTH) {
2788                         new_value = 1 - dist / WM_RADIAL_CONTROL_DISPLAY_SIZE;
2789                 } else if(mode == WM_RADIALCONTROL_ANGLE)
2790                         new_value = ((int)(atan2f(delta[1], delta[0]) * (float)(180.0 / M_PI)) + 180);
2791                 
2792                 if(event->ctrl) {
2793                         if(mode == WM_RADIALCONTROL_STRENGTH)
2794                                 new_value = ((int)ceilf(new_value * 10.f) * 10.0f) / 100.f;
2795                         else
2796                                 new_value = ((int)new_value + 5) / 10*10;
2797                 }
2798                 
2799                 break;
2800         case ESCKEY:
2801         case RIGHTMOUSE:
2802                 ret = OPERATOR_CANCELLED;
2803                 break;
2804         case LEFTMOUSE:
2805         case PADENTER:
2806                 op->type->exec(C, op);
2807                 ret = OPERATOR_FINISHED;
2808                 break;
2809         }
2810
2811         /* Clamp */
2812         if(new_value > rc->max_value)
2813                 new_value = rc->max_value;
2814         else if(new_value < 0)
2815                 new_value = 0;
2816
2817         /* Update paint data */
2818         rc->value = (float)new_value;
2819
2820         RNA_float_set(op->ptr, "new_value", rc->value);
2821
2822         if(ret != OPERATOR_RUNNING_MODAL) {
2823                 WM_paint_cursor_end(CTX_wm_manager(C), rc->cursor);
2824                 MEM_freeN(rc);
2825         }
2826         
2827         ED_region_tag_redraw(CTX_wm_region(C));
2828
2829         //if (ret != OPERATOR_RUNNING_MODAL) {
2830         //      wmWindow *win = CTX_wm_window(C);
2831         //      WM_cursor_restore(win);
2832         //}
2833
2834         return ret;
2835 }
2836
2837 /* Expects the operator customdata to be an ImBuf (or NULL) */
2838 int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2839 {
2840         wmRadialControl *rc = MEM_callocN(sizeof(wmRadialControl), "radial control");
2841         // wmWindow *win = CTX_wm_window(C);
2842         int mode = RNA_enum_get(op->ptr, "mode");
2843         float initial_value = RNA_float_get(op->ptr, "initial_value");
2844         //float initial_size = RNA_float_get(op->ptr, "initial_size");
2845         int mouse[2];
2846
2847         mouse[0]= event->x;
2848         mouse[1]= event->y;
2849
2850         //if (initial_size == 0)
2851         //      initial_size = WM_RADIAL_CONTROL_DISPLAY_SIZE;
2852
2853         if(mode == WM_RADIALCONTROL_SIZE) {
2854                 rc->max_value = 200;
2855                 mouse[0]-= (int)initial_value;
2856         }
2857         else if(mode == WM_RADIALCONTROL_STRENGTH) {
2858                 rc->max_value = 1;
2859                 mouse[0]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * (1.0f - initial_value));
2860         }
2861         else if(mode == WM_RADIALCONTROL_ANGLE) {
2862                 rc->max_value = 360;
2863                 mouse[0]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value));
2864                 mouse[1]-= (int)(WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value));
2865                 initial_value *= 180.0f/(float)M_PI;
2866         }
2867
2868         if(op->customdata) {
2869                 ImBuf *im = (ImBuf*)op->customdata;
2870                 /* Build GL texture */
2871                 glGenTextures(1, &rc->tex);
2872                 glBindTexture(GL_TEXTURE_2D, rc->tex);
2873                 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, im->x, im->y, 0, GL_ALPHA, GL_FLOAT, im->rect_float);
2874                 MEM_freeN(im->rect_float);
2875                 MEM_freeN(im);
2876         }
2877
2878         RNA_float_get_array(op->ptr, "color", rc->col);
2879         RNA_float_get_array(op->ptr, "texture_color", rc->tex_col);
2880
2881         RNA_int_set_array(op->ptr, "initial_mouse", mouse);
2882         RNA_float_set(op->ptr, "new_value", initial_value);
2883                 
2884         op->customdata = rc;
2885         rc->mode = mode;
2886         rc->initial_value = initial_value;
2887         rc->initial_mouse[0] = mouse[0];
2888         rc->initial_mouse[1] = mouse[1];
2889         rc->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), op->type->poll,
2890                                                   wm_radial_control_paint, op->customdata);
2891
2892         //WM_cursor_modal(win, CURSOR_NONE);
2893
2894         /* add modal handler */
2895         WM_event_add_modal_handler(C, op);
2896         
2897         WM_radial_control_modal(C, op, event);
2898         
2899         return OPERATOR_RUNNING_MODAL;
2900 }
2901
2902 /* Gets a descriptive string of the operation */
2903 void WM_radial_control_string(wmOperator *op, char str[], int maxlen)
2904 {
2905         int mode = RNA_enum_get(op->ptr, "mode");
2906         float v = RNA_float_get(op->ptr, "new_value");
2907
2908         if(mode == WM_RADIALCONTROL_SIZE)
2909                 BLI_snprintf(str, maxlen, "Size: %d", (int)v);
2910         else if(mode == WM_RADIALCONTROL_STRENGTH)
2911                 BLI_snprintf(str, maxlen, "Strength: %d", (int)v);
2912         else if(mode == WM_RADIALCONTROL_ANGLE)
2913                 BLI_snprintf(str, maxlen, "Angle: %d", (int)(v * 180.0f/(float)M_PI));
2914 }
2915
2916 /** Important: this doesn't define an actual operator, it
2917         just sets up the common parts of the radial control op. **/
2918 void WM_OT_radial_control_partial(wmOperatorType *ot)
2919 {
2920         static EnumPropertyItem radial_mode_items[] = {
2921                 {WM_RADIALCONTROL_SIZE, "SIZE", 0, "Size", ""},
2922                 {WM_RADIALCONTROL_STRENGTH, "STRENGTH", 0, "Strength", ""},
2923                 {WM_RADIALCONTROL_ANGLE, "ANGLE", 0, "Angle", ""},
2924                 {0, NULL, 0, NULL, NULL}};
2925         static float color[4] = {1.0f, 1.0f, 1.0f, 0.5f};
2926         static float tex_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
2927
2928         /* Should be set in custom invoke() */
2929         RNA_def_float(ot->srna, "initial_value", 0, 0, FLT_MAX, "Initial Value", "", 0, FLT_MAX);
2930
2931         /* Set internally, should be used in custom exec() to get final value */
2932         RNA_def_float(ot->srna, "new_value", 0, 0, FLT_MAX, "New Value", "", 0, FLT_MAX);
2933
2934         /* Should be set before calling operator */
2935         RNA_def_enum(ot->srna, "mode", radial_mode_items, 0, "Mode", "");
2936
2937         /* Internal */
2938         RNA_def_int_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "Initial Mouse", "", INT_MIN, INT_MAX);
2939
2940         RNA_def_float_color(ot->srna, "color", 4, color, 0.0f, FLT_MAX, "Color", "Radial control color", 0.0f, 1.0f);
2941         RNA_def_float_color(ot->srna, "texture_color", 4, tex_color, 0.0f, FLT_MAX, "Texture Color", "Radial control texture color", 0.0f, 1.0f);
2942 }
2943
2944 /* ************************** timer for testing ***************** */
2945
2946 /* uses no type defines, fully local testing function anyway... ;) */
2947
2948 static void redraw_timer_window_swap(bContext *C)
2949 {
2950         wmWindow *win= CTX_wm_window(C);
2951         ScrArea *sa;
2952
2953         for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next)
2954                 ED_area_tag_redraw(sa);
2955         wm_draw_update(C);
2956
2957         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
2958 }
2959
2960 static EnumPropertyItem redraw_timer_type_items[] = {
2961         {0, "DRAW", 0, "Draw Region", "Draw Region"},
2962         {1, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"},
2963         {2, "DRAW_WIN", 0, "Draw Window", "Draw Window"},
2964         {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"},
2965         {4, "ANIM_STEP", 0, "Anim Step", "Animation Steps"},
2966         {5, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"},
2967         {6, "UNDO", 0, "Undo/Redo", "Undo/Redo"},
2968         {0, NULL, 0, NULL, NULL}};
2969
2970 static int redraw_timer_exec(bContext *C, wmOperator *op)
2971 {
2972         ARegion *ar= CTX_wm_region(C);
2973         double stime= PIL_check_seconds_timer();
2974         int type = RNA_enum_get(op->ptr, "type");
2975         int iter = RNA_int_get(op->ptr, "iterations");
2976         int a;
2977         float time;
2978         const char *infostr= "";
2979         
2980         WM_cursor_wait(1);
2981
2982         for(a=0; a<iter; a++) {
2983                 if (type==0) {
2984                         if(ar)
2985                                 ED_region_do_draw(C, ar);
2986                 } 
2987                 else if (type==1) {
2988                         wmWindow *win= CTX_wm_window(C);
2989                         
2990                         ED_region_tag_redraw(ar);
2991                         wm_draw_update(C);
2992                         
2993                         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
2994                 }
2995                 else if (type==2) {
2996                         wmWindow *win= CTX_wm_window(C);
2997                         ScrArea *sa;
2998                         
2999                         ScrArea *sa_back= CTX_wm_area(C);
3000                         ARegion *ar_back= CTX_wm_region(C);
3001
3002                         for(sa= CTX_wm_screen(C)->areabase.first; sa; sa= sa->next) {
3003                                 ARegion *ar_iter;
3004                                 CTX_wm_area_set(C, sa);
3005
3006                                 for(ar_iter= sa->regionbase.first; ar_iter; ar_iter= ar_iter->next) {
3007                                         if(ar_iter->swinid) {
3008                                                 CTX_wm_region_set(C, ar_iter);
3009                                                 ED_region_do_draw(C, ar_iter);
3010                                         }
3011                                 }
3012                         }
3013
3014                         CTX_wm_window_set(C, win);      /* XXX context manipulation warning! */
3015
3016                         CTX_wm_area_set(C, sa_back);
3017                         CTX_wm_region_set(C, ar_back);
3018                 }
3019                 else if (type==3) {
3020                         redraw_timer_window_swap(C);
3021                 }
3022                 else if (type==4) {
3023                         Main *bmain= CTX_data_main(C);
3024                         Scene *scene= CTX_data_scene(C);
3025                         
3026                         if(a & 1) scene->r.cfra--;
3027                         else scene->r.cfra++;
3028                         scene_update_for_newframe(bmain, scene, scene->lay);
3029                 }
3030                 else if (type==5) {
3031
3032                         /* play anim, return on same frame as started with */
3033                         Main *bmain= CTX_data_main(C);
3034                         Scene *scene= CTX_data_scene(C);
3035                         int tot= (scene->r.efra - scene->r.sfra) + 1;
3036
3037                         while(tot--) {
3038                                 /* todo, ability to escape! */
3039                                 scene->r.cfra++;
3040                                 if(scene->r.cfra > scene->r.efra)
3041                                         scene->r.cfra= scene->r.sfra;
3042
3043                                 scene_update_for_newframe(bmain, scene, scene->lay);
3044                                 redraw_timer_window_swap(C);
3045                         }
3046                 }
3047                 else { /* 6 */
3048                         ED_undo_pop(C);
3049                         ED_undo_redo(C);
3050                 }
3051         }
3052         
3053         time= (float)((PIL_check_seconds_timer()-stime)*1000);
3054
3055         RNA_enum_description(redraw_timer_type_items, type, &infostr);
3056
3057         WM_cursor_wait(0);
3058
3059         BKE_reportf(op->reports, RPT_WARNING, "%d x %s: %.2f ms,  average: %.4f", iter, infostr, time, time/iter);
3060         
3061         return OPERATOR_FINISHED;
3062 }
3063
3064 static void WM_OT_redraw_timer(wmOperatorType *ot)
3065 {
3066         ot->name= "Redraw Timer";
3067         ot->idname= "WM_OT_redraw_timer";
3068         ot->description="Simple redraw timer to test the speed of updating the interface";
3069
3070         ot->invoke= WM_menu_invoke;
3071         ot->exec= redraw_timer_exec;
3072         ot->poll= WM_operator_winactive;
3073
3074         ot->prop= RNA_def_enum(ot->srna, "type", redraw_timer_type_items, 0, "Type", "");
3075         RNA_def_int(ot->srna, "iterations", 10, 1,INT_MAX, "Iterations", "Number of times to redraw", 1,1000);
3076
3077 }
3078
3079 /* ************************** memory statistics for testing ***************** */
3080
3081 static int memory_statistics_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
3082 {
3083         MEM_printmemlist_stats();
3084         return OPERATOR_FINISHED;
3085 }
3086
3087 static void WM_OT_memory_statistics(wmOperatorType *ot)
3088 {
3089         ot->name= "Memory Statistics";
3090         ot->idname= "WM_OT_memory_statistics";
3091         ot->description= "Print memory statistics to the console";
3092         
3093         ot->exec= memory_statistics_exec;
3094 }
3095
3096 /* ******************************************************* */
3097  
3098 /* called on initialize WM_exit() */
3099 void wm_operatortype_free(void)
3100 {
3101         wmOperatorType *ot;
3102         
3103         for(ot= global_ops.first; ot; ot= ot->next) {
3104                 if(ot->macro.first)
3105                         wm_operatortype_free_macro(ot);
3106
3107                 if(ot->ext.srna) /* python operator, allocs own string */
3108                         MEM_freeN((void *)ot->idname);
3109         }
3110         
3111         BLI_freelistN(&global_ops);
3112 }
3113
3114 /* called on initialize WM_init() */
3115 void wm_operatortype_init(void)
3116 {
3117         WM_operatortype_append(WM_OT_window_duplicate);
3118         WM_operatortype_append(WM_OT_read_homefile);
3119         WM_operatortype_append(WM_OT_read_factory_settings);
3120         WM_operatortype_append(WM_OT_save_homefile);
3121         WM_operatortype_append(WM_OT_window_fullscreen_toggle);
3122         WM_operatortype_append(WM_OT_quit_blender);
3123         WM_operatortype_append(WM_OT_open_mainfile);
3124         WM_operatortype_append(WM_OT_link_append);
3125         WM_operatortype_append(WM_OT_recover_last_session);
3126         WM_operatortype_append(WM_OT_recover_auto_save);
3127         WM_operatortype_append(WM_OT_save_as_mainfile);
3128         WM_operatortype_append(WM_OT_save_mainfile);
3129         WM_operatortype_append(WM_OT_redraw_timer);
3130         WM_operatortype_append(WM_OT_memory_statistics);
3131         WM_operatortype_append(WM_OT_debug_menu);
3132         WM_operatortype_append(WM_OT_splash);
3133         WM_operatortype_append(WM_OT_search_menu);
3134         WM_operatortype_append(WM_OT_call_menu);
3135 #if defined(WIN32)
3136         WM_operatortype_append(WM_OT_console_toggle);
3137 #endif
3138
3139 #ifdef WITH_COLLADA
3140         /* XXX: move these */
3141         WM_operatortype_append(WM_OT_collada_export);
3142         WM_operatortype_append(WM_OT_collada_import);
3143 #endif
3144
3145 }
3146
3147 /* circleselect-like modal operators */
3148 static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
3149 {
3150         static EnumPropertyItem modal_items[] = {
3151         {GESTURE_MODAL_CANCEL,  "CANCEL", 0, "Cancel", ""},
3152         {GESTURE_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
3153         {GESTURE_MODAL_CIRCLE_ADD, "ADD", 0, "Add", ""},
3154         {GESTURE_MODAL_CIRCLE_SUB, "SUBTRACT", 0, "Subtract", ""},
3155
3156         {GESTURE_MODAL_SELECT,  "SELECT", 0, "Select", ""},
3157         {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""},
3158         {GESTURE_MODAL_NOP,"NOP", 0, "No Operation", ""},
3159
3160
3161         {0, NULL, 0, NULL, NULL}};
3162
3163         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Gesture Circle");
3164
3165         /* this function is called for each spacetype, only needs to add map once */
3166         if(keymap) return;
3167
3168         keymap= WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items);
3169
3170         /* items for modal map */
3171         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3172         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3173
3174         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CONFIRM);
3175         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, 0, 0, GESTURE_MODAL_CONFIRM);
3176
3177         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_SELECT);
3178
3179 #if 0 // Durien guys like this :S
3180         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
3181         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_NOP);
3182 #else
3183         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_DESELECT); //  defailt 2.4x
3184         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP); //  defailt 2.4x
3185 #endif
3186
3187         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_NOP);
3188
3189         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
3190         WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_SUB);
3191         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
3192         WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, GESTURE_MODAL_CIRCLE_ADD);
3193
3194         /* assign map to operators */
3195         WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle");
3196         WM_modalkeymap_assign(keymap, "UV_OT_circle_select");
3197
3198 }
3199
3200 /* straight line modal operators */
3201 static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
3202 {
3203         static EnumPropertyItem modal_items[] = {
3204                 {GESTURE_MODAL_CANCEL,  "CANCEL", 0, "Cancel", ""},
3205                 {GESTURE_MODAL_SELECT,  "SELECT", 0, "Select", ""},
3206                 {GESTURE_MODAL_BEGIN,   "BEGIN", 0, "Begin", ""},
3207                 {0, NULL, 0, NULL, NULL}};
3208         
3209         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Straight Line");
3210         
3211         /* this function is called for each spacetype, only needs to add map once */
3212         if(keymap) return;
3213         
3214         keymap= WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items);
3215         
3216         /* items for modal map */
3217         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3218         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3219         
3220         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
3221         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_SELECT);
3222         
3223         /* assign map to operators */
3224         WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line");
3225 }
3226
3227
3228 /* borderselect-like modal operators */
3229 static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
3230 {
3231         static EnumPropertyItem modal_items[] = {
3232         {GESTURE_MODAL_CANCEL,  "CANCEL", 0, "Cancel", ""},
3233         {GESTURE_MODAL_SELECT,  "SELECT", 0, "Select", ""},
3234         {GESTURE_MODAL_DESELECT,"DESELECT", 0, "DeSelect", ""},
3235         {GESTURE_MODAL_BEGIN,   "BEGIN", 0, "Begin", ""},
3236         {0, NULL, 0, NULL, NULL}};
3237
3238         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Gesture Border");
3239
3240         /* this function is called for each spacetype, only needs to add map once */
3241         if(keymap) return;
3242
3243         keymap= WM_modalkeymap_add(keyconf, "Gesture Border", modal_items);
3244
3245         /* items for modal map */
3246         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3247         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL);
3248
3249         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
3250         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT);
3251
3252 #if 0 // Durian guys like this
3253         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_BEGIN);
3254         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_SHIFT, 0, GESTURE_MODAL_DESELECT);
3255 #else
3256         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN);
3257         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, 0, 0, GESTURE_MODAL_DESELECT);
3258 #endif
3259
3260         /* assign map to operators */
3261         WM_modalkeymap_assign(keymap, "ACTION_OT_select_border");
3262         WM_modalkeymap_assign(keymap, "ANIM_OT_channels_select_border");
3263         WM_modalkeymap_assign(keymap, "ANIM_OT_previewrange_set");
3264         WM_modalkeymap_assign(keymap, "INFO_OT_select_border");
3265         WM_modalkeymap_assign(keymap, "FILE_OT_select_border");
3266         WM_modalkeymap_assign(keymap, "GRAPH_OT_select_border");
3267         WM_modalkeymap_assign(keymap, "MARKER_OT_select_border");
3268         WM_modalkeymap_assign(keymap, "NLA_OT_select_border");
3269         WM_modalkeymap_assign(keymap, "NODE_OT_select_border");
3270 //      WM_modalkeymap_assign(keymap, "SCREEN_OT_border_select"); // template
3271         WM_modalkeymap_assign(keymap, "SEQUENCER_OT_select_border");
3272         WM_modalkeymap_assign(keymap, "SEQUENCER_OT_view_ghost_border");
3273         WM_modalkeymap_assign(keymap, "UV_OT_select_border");
3274         WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
3275         WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
3276         WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
3277         WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
3278         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); // XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel
3279 }
3280
3281 /* zoom to border modal operators */
3282 static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
3283 {
3284         static EnumPropertyItem modal_items[] = {