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