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