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