Cleanup: wrapped function indentation
[blender.git] / source / blender / editors / interface / interface_ops.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) 2009 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation, Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface_ops.c
27  *  \ingroup edinterface
28  */
29
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_screen_types.h"
35 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math_color.h"
39
40 #include "BLF_api.h"
41 #include "BLF_translation.h"
42
43 #include "BKE_context.h"
44 #include "BKE_screen.h"
45 #include "BKE_global.h"
46 #include "BKE_text.h" /* for UI_OT_reports_to_text */
47 #include "BKE_report.h"
48
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51
52 #include "UI_interface.h"
53
54 #include "interface_intern.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_paint.h"
60
61 /* only for UI_OT_editsource */
62 #include "ED_screen.h"
63 #include "BKE_main.h"
64 #include "BLI_ghash.h"
65
66 /* Reset Default Theme ------------------------ */
67
68 static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
69 {
70         ui_theme_init_default();
71         ui_style_init_default();
72         WM_event_add_notifier(C, NC_WINDOW, NULL);
73         
74         return OPERATOR_FINISHED;
75 }
76
77 static void UI_OT_reset_default_theme(wmOperatorType *ot)
78 {
79         /* identifiers */
80         ot->name = "Reset to Default Theme";
81         ot->idname = "UI_OT_reset_default_theme";
82         ot->description = "Reset to the default theme colors";
83         
84         /* callbacks */
85         ot->exec = reset_default_theme_exec;
86         
87         /* flags */
88         ot->flag = OPTYPE_REGISTER;
89 }
90
91 /* Copy Data Path Operator ------------------------ */
92
93 static int copy_data_path_button_poll(bContext *C)
94 {
95         PointerRNA ptr;
96         PropertyRNA *prop;
97         char *path;
98         int index;
99
100         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
101
102         if (ptr.id.data && ptr.data && prop) {
103                 path = RNA_path_from_ID_to_property(&ptr, prop);
104                 
105                 if (path) {
106                         MEM_freeN(path);
107                         return 1;
108                 }
109         }
110
111         return 0;
112 }
113
114 static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
115 {
116         PointerRNA ptr;
117         PropertyRNA *prop;
118         char *path;
119         int index;
120
121         /* try to create driver using property retrieved from UI */
122         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
123
124         if (ptr.id.data && ptr.data && prop) {
125                 path = RNA_path_from_ID_to_property(&ptr, prop);
126                 
127                 if (path) {
128                         WM_clipboard_text_set(path, false);
129                         MEM_freeN(path);
130                         return OPERATOR_FINISHED;
131                 }
132         }
133
134         return OPERATOR_CANCELLED;
135 }
136
137 static void UI_OT_copy_data_path_button(wmOperatorType *ot)
138 {
139         /* identifiers */
140         ot->name = "Copy Data Path";
141         ot->idname = "UI_OT_copy_data_path_button";
142         ot->description = "Copy the RNA data path for this property to the clipboard";
143
144         /* callbacks */
145         ot->exec = copy_data_path_button_exec;
146         ot->poll = copy_data_path_button_poll;
147
148         /* flags */
149         ot->flag = OPTYPE_REGISTER;
150 }
151
152 /* Reset to Default Values Button Operator ------------------------ */
153
154 static int operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
155 {
156         ID *id = ptr->id.data;
157
158         /* perform updates required for this property */
159         RNA_property_update(C, ptr, prop);
160
161         /* as if we pressed the button */
162         UI_context_active_but_prop_handle(C);
163
164         /* Since we don't want to undo _all_ edits to settings, eg window
165          * edits on the screen or on operator settings.
166          * it might be better to move undo's inline - campbell */
167         if (id && ID_CHECK_UNDO(id)) {
168                 /* do nothing, go ahead with undo */
169                 return OPERATOR_FINISHED;
170         }
171         else {
172                 return OPERATOR_CANCELLED;
173         }
174 }
175
176 static int reset_default_button_poll(bContext *C)
177 {
178         PointerRNA ptr;
179         PropertyRNA *prop;
180         int index;
181
182         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
183         
184         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
185 }
186
187 static int reset_default_button_exec(bContext *C, wmOperator *op)
188 {
189         PointerRNA ptr;
190         PropertyRNA *prop;
191         int index;
192         const bool all = RNA_boolean_get(op->ptr, "all");
193
194         /* try to reset the nominated setting to its default value */
195         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
196         
197         /* if there is a valid property that is editable... */
198         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
199                 if (RNA_property_reset(&ptr, prop, (all) ? -1 : index))
200                         return operator_button_property_finish(C, &ptr, prop);
201         }
202
203         return OPERATOR_CANCELLED;
204 }
205
206 static void UI_OT_reset_default_button(wmOperatorType *ot)
207 {
208         /* identifiers */
209         ot->name = "Reset to Default Value";
210         ot->idname = "UI_OT_reset_default_button";
211         ot->description = "Reset this property's value to its default value";
212
213         /* callbacks */
214         ot->poll = reset_default_button_poll;
215         ot->exec = reset_default_button_exec;
216
217         /* flags */
218         ot->flag = OPTYPE_UNDO;
219         
220         /* properties */
221         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
222 }
223
224 /* Unset Property Button Operator ------------------------ */
225
226 static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
227 {
228         PointerRNA ptr;
229         PropertyRNA *prop;
230         int index;
231
232         /* try to unset the nominated property */
233         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
234
235         /* if there is a valid property that is editable... */
236         if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
237             /* RNA_property_is_idprop(prop) && */
238             RNA_property_is_set(&ptr, prop))
239         {
240                 RNA_property_unset(&ptr, prop);
241                 return operator_button_property_finish(C, &ptr, prop);
242         }
243
244         return OPERATOR_CANCELLED;
245 }
246
247 static void UI_OT_unset_property_button(wmOperatorType *ot)
248 {
249         /* identifiers */
250         ot->name = "Unset property";
251         ot->idname = "UI_OT_unset_property_button";
252         ot->description = "Clear the property and use default or generated value in operators";
253
254         /* callbacks */
255         ot->poll = ED_operator_regionactive;
256         ot->exec = unset_property_button_exec;
257
258         /* flags */
259         ot->flag = OPTYPE_UNDO;
260 }
261
262 /* Copy To Selected Operator ------------------------ */
263
264 static bool copy_to_selected_list(
265         bContext *C, PointerRNA *ptr, PropertyRNA *prop,
266         ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
267 {
268         *r_use_path_from_id = false;
269         *r_path = NULL;
270
271         if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
272                 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
273         }
274         else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
275                 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
276         }
277         else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
278                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
279         }
280         else if (ptr->id.data) {
281                 ID *id = ptr->id.data;
282
283                 if (GS(id->name) == ID_OB) {
284                         *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
285                         *r_use_path_from_id = true;
286                         *r_path = RNA_path_from_ID_to_property(ptr, prop);
287                 }
288                 else if (GS(id->name) == ID_SCE) {
289                         /* Sequencer's ID is scene :/ */
290                         /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
291                         if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
292                                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
293                         }
294                 }
295                 return (*r_path != NULL);
296         }
297         else {
298                 return false;
299         }
300
301         return true;
302 }
303
304 /**
305  * called from both exec & poll
306  *
307  * \note: normally we wouldn't call a loop from within a poll function,
308  * However this is a special case, and for regular poll calls, getting
309  * the context from the button will fail early.
310  */
311 static bool copy_to_selected_button(bContext *C, bool all, bool poll)
312 {
313         PointerRNA ptr, lptr, idptr;
314         PropertyRNA *prop, *lprop;
315         bool success = false;
316         int index;
317
318         /* try to reset the nominated setting to its default value */
319         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
320
321         /* if there is a valid property that is editable... */
322         if (ptr.data && prop) {
323                 char *path = NULL;
324                 bool use_path_from_id;
325                 CollectionPointerLink *link;
326                 ListBase lb;
327
328                 if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
329                         return success;
330
331                 for (link = lb.first; link; link = link->next) {
332                         if (link->ptr.data != ptr.data) {
333                                 if (use_path_from_id) {
334                                         /* Path relative to ID. */
335                                         lprop = NULL;
336                                         RNA_id_pointer_create(link->ptr.id.data, &idptr);
337                                         RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
338                                 }
339                                 else if (path) {
340                                         /* Path relative to elements from list. */
341                                         lprop = NULL;
342                                         RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
343                                 }
344                                 else {
345                                         lptr = link->ptr;
346                                         lprop = prop;
347                                 }
348
349                                 if (lptr.data == ptr.data) {
350                                         /* lptr might not be the same as link->ptr! */
351                                         continue;
352                                 }
353
354                                 if (lprop == prop) {
355                                         if (RNA_property_editable(&lptr, lprop)) {
356                                                 if (poll) {
357                                                         success = true;
358                                                         break;
359                                                 }
360                                                 else {
361                                                         if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
362                                                                 RNA_property_update(C, &lptr, prop);
363                                                                 success = true;
364                                                         }
365                                                 }
366                                         }
367                                 }
368                         }
369                 }
370
371                 MEM_SAFE_FREE(path);
372                 BLI_freelistN(&lb);
373         }
374
375         return success;
376 }
377
378 static int copy_to_selected_button_poll(bContext *C)
379 {
380         return copy_to_selected_button(C, false, true);
381 }
382
383 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
384 {
385         bool success;
386
387         const bool all = RNA_boolean_get(op->ptr, "all");
388
389         success = copy_to_selected_button(C, all, false);
390
391         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
392 }
393
394 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
395 {
396         /* identifiers */
397         ot->name = "Copy To Selected";
398         ot->idname = "UI_OT_copy_to_selected_button";
399         ot->description = "Copy property from this object to selected objects or bones";
400
401         /* callbacks */
402         ot->poll = copy_to_selected_button_poll;
403         ot->exec = copy_to_selected_button_exec;
404
405         /* flags */
406         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
407
408         /* properties */
409         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
410 }
411
412 /* Reports to Textblock Operator ------------------------ */
413
414 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere 
415  * when there are too many to display...
416  */
417
418 static int reports_to_text_poll(bContext *C)
419 {
420         return CTX_wm_reports(C) != NULL;
421 }
422
423 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
424 {
425         ReportList *reports = CTX_wm_reports(C);
426         Main *bmain = CTX_data_main(C);
427         Text *txt;
428         char *str;
429         
430         /* create new text-block to write to */
431         txt = BKE_text_add(bmain, "Recent Reports");
432         
433         /* convert entire list to a display string, and add this to the text-block
434          *      - if commandline debug option enabled, show debug reports too
435          *      - otherwise, up to info (which is what users normally see)
436          */
437         str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
438
439         if (str) {
440                 BKE_text_write(txt, str);
441                 MEM_freeN(str);
442
443                 return OPERATOR_FINISHED;
444         }
445         else {
446                 return OPERATOR_CANCELLED;
447         }
448 }
449
450 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
451 {
452         /* identifiers */
453         ot->name = "Reports to Text Block";
454         ot->idname = "UI_OT_reports_to_textblock";
455         ot->description = "Write the reports ";
456         
457         /* callbacks */
458         ot->poll = reports_to_text_poll;
459         ot->exec = reports_to_text_exec;
460 }
461
462 #ifdef WITH_PYTHON
463
464 /* ------------------------------------------------------------------------- */
465 /* EditSource Utility funcs and operator,
466  * note, this includes utility functions and button matching checks */
467
468 typedef struct uiEditSourceStore {
469         uiBut but_orig;
470         GHash *hash;
471 } uiEditSourceStore;
472
473 typedef struct uiEditSourceButStore {
474         char py_dbg_fn[FILE_MAX];
475         int py_dbg_ln;
476 } uiEditSourceButStore;
477
478 /* should only ever be set while the edit source operator is running */
479 static struct uiEditSourceStore *ui_editsource_info = NULL;
480
481 bool UI_editsource_enable_check(void)
482 {
483         return (ui_editsource_info != NULL);
484 }
485
486 static void ui_editsource_active_but_set(uiBut *but)
487 {
488         BLI_assert(ui_editsource_info == NULL);
489
490         ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__);
491         memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut));
492
493         ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
494 }
495
496 static void ui_editsource_active_but_clear(void)
497 {
498         BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN);
499         MEM_freeN(ui_editsource_info);
500         ui_editsource_info = NULL;
501 }
502
503 static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
504 {
505 #if 0
506         printf("matching buttons: '%s' == '%s'\n",
507                but_a->drawstr, but_b->drawstr);
508 #endif
509
510         /* this just needs to be a 'good-enough' comparison so we can know beyond
511          * reasonable doubt that these buttons are the same between redraws.
512          * if this fails it only means edit-source fails - campbell */
513         if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) &&
514             (but_a->type == but_b->type) &&
515             (but_a->rnaprop == but_b->rnaprop) &&
516             (but_a->optype == but_b->optype) &&
517             (but_a->unit_type == but_b->unit_type) &&
518             STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR))
519         {
520                 return true;
521         }
522         else {
523                 return false;
524         }
525 }
526
527 void UI_editsource_active_but_test(uiBut *but)
528 {
529         extern void PyC_FileAndNum_Safe(const char **filename, int *lineno);
530
531         struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__);
532
533         const char *fn;
534         int lineno = -1;
535
536 #if 0
537         printf("comparing buttons: '%s' == '%s'\n",
538                but->drawstr, ui_editsource_info->but_orig.drawstr);
539 #endif
540
541         PyC_FileAndNum_Safe(&fn, &lineno);
542
543         if (lineno != -1) {
544                 BLI_strncpy(but_store->py_dbg_fn, fn,
545                             sizeof(but_store->py_dbg_fn));
546                 but_store->py_dbg_ln = lineno;
547         }
548         else {
549                 but_store->py_dbg_fn[0] = '\0';
550                 but_store->py_dbg_ln = -1;
551         }
552
553         BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
554 }
555
556 static int editsource_text_edit(
557         bContext *C, wmOperator *op,
558         char filepath[FILE_MAX], int line)
559 {
560         struct Main *bmain = CTX_data_main(C);
561         Text *text;
562
563         for (text = bmain->text.first; text; text = text->id.next) {
564                 if (text->name && BLI_path_cmp(text->name, filepath) == 0) {
565                         break;
566                 }
567         }
568
569         if (text == NULL) {
570                 text = BKE_text_load(bmain, filepath, bmain->name);
571         }
572
573         if (text == NULL) {
574                 BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
575                 return OPERATOR_CANCELLED;
576         }
577         else {
578                 /* naughty!, find text area to set, not good behavior
579                  * but since this is a dev tool lets allow it - campbell */
580                 ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
581                 if (sa) {
582                         SpaceText *st = sa->spacedata.first;
583                         st->text = text;
584                 }
585                 else {
586                         BKE_reportf(op->reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2);
587                 }
588
589                 txt_move_toline(text, line - 1, false);
590                 WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, text);
591         }
592
593         return OPERATOR_FINISHED;
594 }
595
596 static int editsource_exec(bContext *C, wmOperator *op)
597 {
598         uiBut *but = UI_context_active_but_get(C);
599
600         if (but) {
601                 GHashIterator ghi;
602                 struct uiEditSourceButStore *but_store = NULL;
603
604                 ARegion *ar = CTX_wm_region(C);
605                 int ret;
606
607                 /* needed else the active button does not get tested */
608                 UI_screen_free_active_but(C, CTX_wm_screen(C));
609
610                 // printf("%s: begin\n", __func__);
611
612                 /* take care not to return before calling ui_editsource_active_but_clear */
613                 ui_editsource_active_but_set(but);
614
615                 /* redraw and get active button python info */
616                 ED_region_do_draw(C, ar);
617                 ar->do_draw = false;
618
619                 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
620                      BLI_ghashIterator_done(&ghi) == false;
621                      BLI_ghashIterator_step(&ghi))
622                 {
623                         uiBut *but_key = BLI_ghashIterator_getKey(&ghi);
624                         if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
625                                 but_store = BLI_ghashIterator_getValue(&ghi);
626                                 break;
627                         }
628
629                 }
630
631                 if (but_store) {
632                         if (but_store->py_dbg_ln != -1) {
633                                 ret = editsource_text_edit(C, op,
634                                                            but_store->py_dbg_fn,
635                                                            but_store->py_dbg_ln);
636                         }
637                         else {
638                                 BKE_report(op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
639                                 ret = OPERATOR_CANCELLED;
640                         }
641                 }
642                 else {
643                         BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
644                         ret = OPERATOR_CANCELLED;
645                 }
646
647
648                 ui_editsource_active_but_clear();
649
650                 // printf("%s: end\n", __func__);
651
652                 return ret;
653         }
654         else {
655                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
656                 return OPERATOR_CANCELLED;
657         }
658 }
659
660 static void UI_OT_editsource(wmOperatorType *ot)
661 {
662         /* identifiers */
663         ot->name = "Edit Source";
664         ot->idname = "UI_OT_editsource";
665         ot->description = "Edit UI source code of the active button";
666
667         /* callbacks */
668         ot->exec = editsource_exec;
669 }
670
671 /* ------------------------------------------------------------------------- */
672 /* EditTranslation utility funcs and operator,
673  * Note: this includes utility functions and button matching checks.
674  *       this only works in conjunction with a py operator! */
675
676 static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
677 {
678         char tstr[32]; /* Should be more than enough! */
679
680         /* First, full lang code. */
681         BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
682         BLI_join_dirfile(path, maxlen, root, uilng);
683         BLI_path_append(path, maxlen, tstr);
684         if (BLI_is_file(path))
685                 return;
686
687         /* Now try without the second iso code part (_ES in es_ES). */
688         {
689                 const char *tc = NULL;
690                 size_t szt = 0;
691                 tstr[0] = '\0';
692
693                 tc = strchr(uilng, '_');
694                 if (tc) {
695                         szt = tc - uilng;
696                         if (szt < sizeof(tstr)) /* Paranoid, should always be true! */
697                                 BLI_strncpy(tstr, uilng, szt + 1); /* +1 for '\0' char! */
698                 }
699                 if (tstr[0]) {
700                         /* Because of some codes like sr_SR@latin... */
701                         tc = strchr(uilng, '@');
702                         if (tc)
703                                 BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
704
705                         BLI_join_dirfile(path, maxlen, root, tstr);
706                         strcat(tstr, ".po");
707                         BLI_path_append(path, maxlen, tstr);
708                         if (BLI_is_file(path))
709                                 return;
710                 }
711         }
712
713         /* Else no po file! */
714         path[0] = '\0';
715 }
716
717 static int edittranslation_exec(bContext *C, wmOperator *op)
718 {
719         uiBut *but = UI_context_active_but_get(C);
720         int ret = OPERATOR_CANCELLED;
721
722         if (but) {
723                 wmOperatorType *ot;
724                 PointerRNA ptr;
725                 char popath[FILE_MAX];
726                 const char *root = U.i18ndir;
727                 const char *uilng = BLF_lang_get();
728
729                 uiStringInfo but_label = {BUT_GET_LABEL, NULL};
730                 uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
731                 uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
732                 uiStringInfo but_tip = {BUT_GET_TIP, NULL};
733                 uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL};
734                 uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
735                 uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
736                 uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
737                 uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL};
738                 uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL};
739
740                 if (!BLI_is_dir(root)) {
741                         BKE_report(op->reports, RPT_ERROR, "Please set your User Preferences' 'Translation Branches "
742                                                            "Directory' path to a valid directory");
743                         return OPERATOR_CANCELLED;
744                 }
745                 ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
746                 if (ot == NULL) {
747                         BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
748                                                             "in the User Preferences", EDTSRC_I18N_OP_NAME);
749                         return OPERATOR_CANCELLED;
750                 }
751                 /* Try to find a valid po file for current language... */
752                 edittranslation_find_po_file(root, uilng, popath, FILE_MAX);
753 /*              printf("po path: %s\n", popath);*/
754                 if (popath[0] == '\0') {
755                         BKE_reportf(op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root);
756                         return OPERATOR_CANCELLED;
757                 }
758
759                 UI_but_string_info_get(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
760                                 &rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);
761
762                 WM_operator_properties_create_ptr(&ptr, ot);
763                 RNA_string_set(&ptr, "lang", uilng);
764                 RNA_string_set(&ptr, "po_file", popath);
765                 RNA_string_set(&ptr, "but_label", but_label.strinfo);
766                 RNA_string_set(&ptr, "rna_label", rna_label.strinfo);
767                 RNA_string_set(&ptr, "enum_label", enum_label.strinfo);
768                 RNA_string_set(&ptr, "but_tip", but_tip.strinfo);
769                 RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo);
770                 RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo);
771                 RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo);
772                 RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
773                 RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
774                 RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
775                 ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
776
777                 /* Clean up */
778                 if (but_label.strinfo)
779                         MEM_freeN(but_label.strinfo);
780                 if (rna_label.strinfo)
781                         MEM_freeN(rna_label.strinfo);
782                 if (enum_label.strinfo)
783                         MEM_freeN(enum_label.strinfo);
784                 if (but_tip.strinfo)
785                         MEM_freeN(but_tip.strinfo);
786                 if (rna_tip.strinfo)
787                         MEM_freeN(rna_tip.strinfo);
788                 if (enum_tip.strinfo)
789                         MEM_freeN(enum_tip.strinfo);
790                 if (rna_struct.strinfo)
791                         MEM_freeN(rna_struct.strinfo);
792                 if (rna_prop.strinfo)
793                         MEM_freeN(rna_prop.strinfo);
794                 if (rna_enum.strinfo)
795                         MEM_freeN(rna_enum.strinfo);
796                 if (rna_ctxt.strinfo)
797                         MEM_freeN(rna_ctxt.strinfo);
798
799                 return ret;
800         }
801         else {
802                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
803                 return OPERATOR_CANCELLED;
804         }
805 }
806
807 static void UI_OT_edittranslation_init(wmOperatorType *ot)
808 {
809         /* identifiers */
810         ot->name = "Edit Translation";
811         ot->idname = "UI_OT_edittranslation_init";
812         ot->description = "Edit i18n in current language for the active button";
813
814         /* callbacks */
815         ot->exec = edittranslation_exec;
816 }
817
818 #endif /* WITH_PYTHON */
819
820 static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
821 {
822         BLF_lang_init();
823         BLF_cache_clear();
824         BLF_lang_set(NULL);
825         UI_reinit_font();
826         return OPERATOR_FINISHED;
827 }
828
829 static void UI_OT_reloadtranslation(wmOperatorType *ot)
830 {
831         /* identifiers */
832         ot->name = "Reload Translation";
833         ot->idname = "UI_OT_reloadtranslation";
834         ot->description = "Force a full reload of UI translation";
835
836         /* callbacks */
837         ot->exec = reloadtranslation_exec;
838 }
839
840 int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
841 {
842         /* should only return true for regions that include buttons, for now
843          * return true always */
844         if (drag->type == WM_DRAG_COLOR) {
845                 SpaceImage *sima = CTX_wm_space_image(C);
846                 ARegion *ar = CTX_wm_region(C);
847
848                 if (UI_but_active_drop_color(C))
849                         return 1;
850
851                 if (sima && (sima->mode == SI_MODE_PAINT) &&
852                     sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
853                 {
854                         return 1;
855                 }
856         }
857
858         return 0;
859 }
860
861 void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
862 {
863         uiDragColorHandle *drag_info = drag->poin;
864
865         RNA_float_set_array(drop->ptr, "color", drag_info->color);
866         RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
867 }
868
869 static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
870 {
871         ARegion *ar = CTX_wm_region(C);
872         uiBut *but = NULL;
873         float color[4];
874         bool gamma;
875
876         RNA_float_get_array(op->ptr, "color", color);
877         gamma = RNA_boolean_get(op->ptr, "gamma");
878
879         /* find button under mouse, check if it has RNA color property and
880          * if it does copy the data */
881         but = ui_but_find_active_in_region(ar);
882
883         if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
884                 const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
885                 BLI_assert(color_len <= 4);
886
887                 /* keep alpha channel as-is */
888                 if (color_len == 4) {
889                         color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
890                 }
891
892                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
893                         if (!gamma)
894                                 ui_block_cm_to_display_space_v3(but->block, color);
895                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
896                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
897                 }
898                 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
899                         if (gamma)
900                                 ui_block_cm_to_scene_linear_v3(but->block, color);
901                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
902                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
903                 }
904         }
905         else {
906                 if (gamma) {
907                         srgb_to_linearrgb_v3_v3(color, color);
908                 }
909
910                 ED_imapaint_bucket_fill(C, color, op);
911         }
912
913         ED_region_tag_redraw(ar);
914
915         return OPERATOR_FINISHED;
916 }
917
918
919 static void UI_OT_drop_color(wmOperatorType *ot)
920 {
921         ot->name = "Drop Color";
922         ot->idname = "UI_OT_drop_color";
923         ot->description = "Drop colors to buttons";
924
925         ot->invoke = drop_color_invoke;
926         ot->flag = OPTYPE_INTERNAL;
927
928         RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
929         RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
930 }
931
932
933
934 /* ********************************************************* */
935 /* Registration */
936
937 void ED_button_operatortypes(void)
938 {
939         WM_operatortype_append(UI_OT_reset_default_theme);
940         WM_operatortype_append(UI_OT_copy_data_path_button);
941         WM_operatortype_append(UI_OT_reset_default_button);
942         WM_operatortype_append(UI_OT_unset_property_button);
943         WM_operatortype_append(UI_OT_copy_to_selected_button);
944         WM_operatortype_append(UI_OT_reports_to_textblock);  /* XXX: temp? */
945         WM_operatortype_append(UI_OT_drop_color);
946 #ifdef WITH_PYTHON
947         WM_operatortype_append(UI_OT_editsource);
948         WM_operatortype_append(UI_OT_edittranslation_init);
949 #endif
950         WM_operatortype_append(UI_OT_reloadtranslation);
951
952         /* external */
953         WM_operatortype_append(UI_OT_eyedropper_color);
954         WM_operatortype_append(UI_OT_eyedropper_id);
955         WM_operatortype_append(UI_OT_eyedropper_depth);
956 }