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