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