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