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