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