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