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