Merge branch 'master' into blender2.8
[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 #include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math_color.h"
40
41 #include "BLF_api.h"
42 #include "BLT_lang.h"
43
44 #include "BKE_context.h"
45 #include "BKE_idprop.h"
46 #include "BKE_layer.h"
47 #include "BKE_screen.h"
48 #include "BKE_global.h"
49 #include "BKE_node.h"
50 #include "BKE_text.h" /* for UI_OT_reports_to_text */
51 #include "BKE_report.h"
52
53 #include "DEG_depsgraph.h"
54
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57 #include "RNA_types.h"
58
59 #include "UI_interface.h"
60
61 #include "interface_intern.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_paint.h"
67
68 /* only for UI_OT_editsource */
69 #include "ED_screen.h"
70 #include "BKE_main.h"
71 #include "BLI_ghash.h"
72
73 /* Reset Default Theme ------------------------ */
74
75 static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
76 {
77         ui_theme_init_default();
78         ui_style_init_default();
79         WM_event_add_notifier(C, NC_WINDOW, NULL);
80         
81         return OPERATOR_FINISHED;
82 }
83
84 static void UI_OT_reset_default_theme(wmOperatorType *ot)
85 {
86         /* identifiers */
87         ot->name = "Reset to Default Theme";
88         ot->idname = "UI_OT_reset_default_theme";
89         ot->description = "Reset to the default theme colors";
90         
91         /* callbacks */
92         ot->exec = reset_default_theme_exec;
93         
94         /* flags */
95         ot->flag = OPTYPE_REGISTER;
96 }
97
98 /* Copy Data Path Operator ------------------------ */
99
100 static int copy_data_path_button_poll(bContext *C)
101 {
102         PointerRNA ptr;
103         PropertyRNA *prop;
104         char *path;
105         int index;
106
107         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
108
109         if (ptr.id.data && ptr.data && prop) {
110                 path = RNA_path_from_ID_to_property(&ptr, prop);
111                 
112                 if (path) {
113                         MEM_freeN(path);
114                         return 1;
115                 }
116         }
117
118         return 0;
119 }
120
121 static int copy_data_path_button_exec(bContext *C, wmOperator *op)
122 {
123         PointerRNA ptr;
124         PropertyRNA *prop;
125         char *path;
126         int index;
127
128         const bool full_path = RNA_boolean_get(op->ptr, "full_path");
129
130         /* try to create driver using property retrieved from UI */
131         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
132
133         if (ptr.id.data != NULL) {
134
135                 if (full_path) {
136
137                         if (prop) {
138                                 path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
139                         }
140                         else {
141                                 path = RNA_path_full_struct_py(&ptr);
142                         }
143                 }
144                 else {
145                         path = RNA_path_from_ID_to_property(&ptr, prop);
146                 }
147
148                 if (path) {
149                         WM_clipboard_text_set(path, false);
150                         MEM_freeN(path);
151                         return OPERATOR_FINISHED;
152                 }
153         }
154
155         return OPERATOR_CANCELLED;
156 }
157
158 static void UI_OT_copy_data_path_button(wmOperatorType *ot)
159 {
160         PropertyRNA *prop;
161
162         /* identifiers */
163         ot->name = "Copy Data Path";
164         ot->idname = "UI_OT_copy_data_path_button";
165         ot->description = "Copy the RNA data path for this property to the clipboard";
166
167         /* callbacks */
168         ot->exec = copy_data_path_button_exec;
169         ot->poll = copy_data_path_button_poll;
170
171         /* flags */
172         ot->flag = OPTYPE_REGISTER;
173
174         /* properties */
175         prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
176         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
177 }
178
179 static int copy_python_command_button_poll(bContext *C)
180 {
181         uiBut *but = UI_context_active_but_get(C);
182
183         if (but && (but->optype != NULL)) {
184                 return 1;
185         }
186
187         return 0;
188 }
189
190 static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op))
191 {
192         uiBut *but = UI_context_active_but_get(C);
193
194         if (but && (but->optype != NULL)) {
195                 PointerRNA *opptr;
196                 char *str;
197                 opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
198
199                 str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
200
201                 WM_clipboard_text_set(str, 0);
202
203                 MEM_freeN(str);
204
205                 return OPERATOR_FINISHED;
206         }
207
208         return OPERATOR_CANCELLED;
209 }
210
211 static void UI_OT_copy_python_command_button(wmOperatorType *ot)
212 {
213         /* identifiers */
214         ot->name = "Copy Python Command";
215         ot->idname = "UI_OT_copy_python_command_button";
216         ot->description = "Copy the Python command matching this button";
217
218         /* callbacks */
219         ot->exec = copy_python_command_button_exec;
220         ot->poll = copy_python_command_button_poll;
221
222         /* flags */
223         ot->flag = OPTYPE_REGISTER;
224 }
225
226 /* Reset to Default Values Button Operator ------------------------ */
227
228 static int operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
229 {
230         ID *id = ptr->id.data;
231
232         /* perform updates required for this property */
233         RNA_property_update(C, ptr, prop);
234
235         /* as if we pressed the button */
236         UI_context_active_but_prop_handle(C);
237
238         /* Since we don't want to undo _all_ edits to settings, eg window
239          * edits on the screen or on operator settings.
240          * it might be better to move undo's inline - campbell */
241         if (id && ID_CHECK_UNDO(id)) {
242                 /* do nothing, go ahead with undo */
243                 return OPERATOR_FINISHED;
244         }
245         else {
246                 return OPERATOR_CANCELLED;
247         }
248 }
249
250 static int reset_default_button_poll(bContext *C)
251 {
252         PointerRNA ptr;
253         PropertyRNA *prop;
254         int index;
255
256         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
257         
258         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
259 }
260
261 static int reset_default_button_exec(bContext *C, wmOperator *op)
262 {
263         PointerRNA ptr;
264         PropertyRNA *prop;
265         int index;
266         const bool all = RNA_boolean_get(op->ptr, "all");
267
268         /* try to reset the nominated setting to its default value */
269         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
270         
271         /* if there is a valid property that is editable... */
272         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
273                 if (RNA_property_reset(&ptr, prop, (all) ? -1 : index))
274                         return operator_button_property_finish(C, &ptr, prop);
275         }
276
277         return OPERATOR_CANCELLED;
278 }
279
280 static void UI_OT_reset_default_button(wmOperatorType *ot)
281 {
282         /* identifiers */
283         ot->name = "Reset to Default Value";
284         ot->idname = "UI_OT_reset_default_button";
285         ot->description = "Reset this property's value to its default value";
286
287         /* callbacks */
288         ot->poll = reset_default_button_poll;
289         ot->exec = reset_default_button_exec;
290
291         /* flags */
292         ot->flag = OPTYPE_UNDO;
293         
294         /* properties */
295         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
296 }
297
298 /* Unset Property Button Operator ------------------------ */
299
300 static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
301 {
302         PointerRNA ptr;
303         PropertyRNA *prop;
304         int index;
305
306         /* try to unset the nominated property */
307         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
308
309         /* if there is a valid property that is editable... */
310         if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
311             /* RNA_property_is_idprop(prop) && */
312             RNA_property_is_set(&ptr, prop))
313         {
314                 RNA_property_unset(&ptr, prop);
315                 return operator_button_property_finish(C, &ptr, prop);
316         }
317
318         return OPERATOR_CANCELLED;
319 }
320
321 static void UI_OT_unset_property_button(wmOperatorType *ot)
322 {
323         /* identifiers */
324         ot->name = "Unset property";
325         ot->idname = "UI_OT_unset_property_button";
326         ot->description = "Clear the property and use default or generated value in operators";
327
328         /* callbacks */
329         ot->poll = ED_operator_regionactive;
330         ot->exec = unset_property_button_exec;
331
332         /* flags */
333         ot->flag = OPTYPE_UNDO;
334 }
335
336 /* Use/Unuse Property Button Operator ------------------------ */
337
338 static int use_property_button_exec(bContext *C, wmOperator *UNUSED(op))
339 {
340         PointerRNA ptr, scene_props_ptr;
341         PropertyRNA *prop;
342         IDProperty *props;
343
344         uiBut *but = UI_context_active_but_get(C);
345
346         prop = but->rnaprop;
347         ptr = but->rnapoin;
348         props = (IDProperty *)ptr.data;
349         /* XXX Using existing data struct to pass another RNAPointer */
350         scene_props_ptr = but->rnasearchpoin;
351
352         const char *identifier = RNA_property_identifier(prop);
353         if (IDP_GetPropertyFromGroup(props, identifier)) {
354                 return OPERATOR_CANCELLED;
355         }
356
357         int array_len = RNA_property_array_length(&scene_props_ptr, prop);
358         bool is_array = array_len != 0;
359
360         switch (RNA_property_type(prop)) {
361                 case PROP_FLOAT:
362                 {
363                         if (is_array) {
364                                 float values[RNA_MAX_ARRAY_LENGTH];
365                                 RNA_property_float_get_array(&scene_props_ptr, prop, values);
366                                 BKE_collection_engine_property_add_float_array(props, identifier, values, array_len);
367                         }
368                         else {
369                                 float value = RNA_property_float_get(&scene_props_ptr, prop);
370                                 BKE_collection_engine_property_add_float(props, identifier, value);
371                         }
372                         break;
373                 }
374                 case PROP_ENUM:
375                 {
376                         int value = RNA_enum_get(&scene_props_ptr, identifier);
377                         BKE_collection_engine_property_add_int(props, identifier, value);
378                         break;
379                 }
380                 case PROP_INT:
381                 {
382                         int value = RNA_int_get(&scene_props_ptr, identifier);
383                         BKE_collection_engine_property_add_int(props, identifier, value);
384                         break;
385                 }
386                 case PROP_BOOLEAN:
387                 {
388                         int value = RNA_boolean_get(&scene_props_ptr, identifier);
389                         BKE_collection_engine_property_add_bool(props, identifier, value);
390                         break;
391                 }
392                 case PROP_STRING:
393                 case PROP_POINTER:
394                 case PROP_COLLECTION:
395                 default:
396                         break;
397         }
398
399         /* TODO(sergey): Use proper flag for tagging here. */
400         DEG_id_tag_update((ID *)CTX_data_scene(C), 0);
401
402         return OPERATOR_FINISHED;
403 }
404
405 static void UI_OT_use_property_button(wmOperatorType *ot)
406 {
407         /* identifiers */
408         ot->name = "Use property";
409         ot->idname = "UI_OT_use_property_button";
410         ot->description = "Create a property";
411
412         /* callbacks */
413         ot->poll = ED_operator_regionactive;
414         ot->exec = use_property_button_exec;
415
416         /* flags */
417         ot->flag = OPTYPE_UNDO;
418 }
419
420 static int unuse_property_button_exec(bContext *C, wmOperator *UNUSED(op))
421 {
422         PointerRNA ptr;
423         PropertyRNA *prop;
424         int index;
425
426         /* try to unset the nominated property */
427         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
428         const char *identifier = RNA_property_identifier(prop);
429
430         IDProperty *props = (IDProperty *)ptr.data;
431         IDProperty *prop_to_remove = IDP_GetPropertyFromGroup(props, identifier);
432         IDP_FreeFromGroup(props, prop_to_remove);
433
434         /* TODO(sergey): Use proper flag for tagging here. */
435         DEG_id_tag_update((ID *)CTX_data_scene(C), 0);
436
437         return OPERATOR_FINISHED;
438 }
439
440 static void UI_OT_unuse_property_button(wmOperatorType *ot)
441 {
442         /* identifiers */
443         ot->name = "Unuse property";
444         ot->idname = "UI_OT_unuse_property_button";
445         ot->description = "Remove a property";
446
447         /* callbacks */
448         ot->poll = ED_operator_regionactive;
449         ot->exec = unuse_property_button_exec;
450
451         /* flags */
452         ot->flag = OPTYPE_UNDO;
453 }
454
455 /* Copy To Selected Operator ------------------------ */
456
457 bool UI_context_copy_to_selected_list(
458         bContext *C, PointerRNA *ptr, PropertyRNA *prop,
459         ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
460 {
461         *r_use_path_from_id = false;
462         *r_path = NULL;
463
464         if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
465                 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
466         }
467         else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
468                 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
469         }
470         else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
471                 ListBase lb;
472                 lb = CTX_data_collection_get(C, "selected_pose_bones");
473
474                 if (!BLI_listbase_is_empty(&lb)) {
475                         CollectionPointerLink *link;
476                         for (link = lb.first; link; link = link->next) {
477                                 bPoseChannel *pchan = link->ptr.data;
478                                 RNA_pointer_create(link->ptr.id.data, &RNA_Bone, pchan->bone, &link->ptr);
479                         }
480                 }
481
482                 *r_lb = lb;
483         }
484         else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
485                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
486         }
487         else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
488                 *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
489         }
490         else if (RNA_struct_is_a(ptr->type, &RNA_Node) ||
491                  RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
492         {
493                 ListBase lb = {NULL, NULL};
494                 char *path = NULL;
495                 bNode *node = NULL;
496
497                 /* Get the node we're editing */
498                 if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
499                         bNodeTree *ntree = ptr->id.data;
500                         bNodeSocket *sock = ptr->data;
501                         if (nodeFindNode(ntree, sock, &node, NULL)) {
502                                 if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
503                                         /* we're good! */
504                                 }
505                                 else {
506                                         node = NULL;
507                                 }
508                         }
509                 }
510                 else {
511                         node = ptr->data;
512                 }
513
514                 /* Now filter by type */
515                 if (node) {
516                         CollectionPointerLink *link, *link_next;
517                         lb = CTX_data_collection_get(C, "selected_nodes");
518
519                         for (link = lb.first; link; link = link_next) {
520                                 bNode *node_data = link->ptr.data;
521                                 link_next = link->next;
522
523                                 if (node_data->type != node->type) {
524                                         BLI_remlink(&lb, link);
525                                         MEM_freeN(link);
526                                 }
527                         }
528                 }
529
530                 *r_lb = lb;
531                 *r_path = path;
532         }
533         else if (ptr->id.data) {
534                 ID *id = ptr->id.data;
535
536                 if (GS(id->name) == ID_OB) {
537                         *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
538                         *r_use_path_from_id = true;
539                         *r_path = RNA_path_from_ID_to_property(ptr, prop);
540                 }
541                 else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
542                         /* check we're using the active object */
543                         const short id_code = GS(id->name);
544                         ListBase lb = CTX_data_collection_get(C, "selected_editable_objects");
545                         char *path = RNA_path_from_ID_to_property(ptr, prop);
546
547                         /* de-duplicate obdata */
548                         if (!BLI_listbase_is_empty(&lb)) {
549                                 CollectionPointerLink *link, *link_next;
550
551                                 for (link = lb.first; link; link = link->next) {
552                                         Object *ob = link->ptr.id.data;
553                                         if (ob->data) {
554                                                 ID *id_data = ob->data;
555                                                 id_data->tag |= LIB_TAG_DOIT;
556                                         }
557                                 }
558
559                                 for (link = lb.first; link; link = link_next) {
560                                         Object *ob = link->ptr.id.data;
561                                         ID *id_data = ob->data;
562                                         link_next = link->next;
563
564                                         if ((id_data == NULL) ||
565                                             (id_data->tag & LIB_TAG_DOIT) == 0 ||
566                                             ID_IS_LINKED(id_data) ||
567                                             (GS(id_data->name) != id_code))
568                                         {
569                                                 BLI_remlink(&lb, link);
570                                                 MEM_freeN(link);
571                                         }
572                                         else {
573                                                 /* avoid prepending 'data' to the path */
574                                                 RNA_id_pointer_create(id_data, &link->ptr);
575                                         }
576
577                                         if (id_data) {
578                                                 id_data->tag &= ~LIB_TAG_DOIT;
579                                         }
580                                 }
581                         }
582
583                         *r_lb = lb;
584                         *r_path = path;
585                 }
586                 else if (GS(id->name) == ID_SCE) {
587                         /* Sequencer's ID is scene :/ */
588                         /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */
589                         if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
590                                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
591                         }
592                 }
593                 return (*r_path != NULL);
594         }
595         else {
596                 return false;
597         }
598
599         return true;
600 }
601
602 /**
603  * called from both exec & poll
604  *
605  * \note: normally we wouldn't call a loop from within a poll function,
606  * However this is a special case, and for regular poll calls, getting
607  * the context from the button will fail early.
608  */
609 static bool copy_to_selected_button(bContext *C, bool all, bool poll)
610 {
611         PointerRNA ptr, lptr, idptr;
612         PropertyRNA *prop, *lprop;
613         bool success = false;
614         int index;
615
616         /* try to reset the nominated setting to its default value */
617         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
618
619         /* if there is a valid property that is editable... */
620         if (ptr.data && prop) {
621                 char *path = NULL;
622                 bool use_path_from_id;
623                 CollectionPointerLink *link;
624                 ListBase lb = {NULL};
625
626                 if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) &&
627                     !BLI_listbase_is_empty(&lb))
628                 {
629                         for (link = lb.first; link; link = link->next) {
630                                 if (link->ptr.data != ptr.data) {
631                                         if (use_path_from_id) {
632                                                 /* Path relative to ID. */
633                                                 lprop = NULL;
634                                                 RNA_id_pointer_create(link->ptr.id.data, &idptr);
635                                                 RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
636                                         }
637                                         else if (path) {
638                                                 /* Path relative to elements from list. */
639                                                 lprop = NULL;
640                                                 RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
641                                         }
642                                         else {
643                                                 lptr = link->ptr;
644                                                 lprop = prop;
645                                         }
646
647                                         if (lptr.data == ptr.data) {
648                                                 /* lptr might not be the same as link->ptr! */
649                                                 continue;
650                                         }
651
652                                         if (lprop == prop) {
653                                                 if (RNA_property_editable(&lptr, lprop)) {
654                                                         if (poll) {
655                                                                 success = true;
656                                                                 break;
657                                                         }
658                                                         else {
659                                                                 if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
660                                                                         RNA_property_update(C, &lptr, prop);
661                                                                         success = true;
662                                                                 }
663                                                         }
664                                                 }
665                                         }
666                                 }
667                         }
668                 }
669                 MEM_SAFE_FREE(path);
670                 BLI_freelistN(&lb);
671         }
672
673         return success;
674 }
675
676 static int copy_to_selected_button_poll(bContext *C)
677 {
678         return copy_to_selected_button(C, false, true);
679 }
680
681 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
682 {
683         bool success;
684
685         const bool all = RNA_boolean_get(op->ptr, "all");
686
687         success = copy_to_selected_button(C, all, false);
688
689         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
690 }
691
692 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
693 {
694         /* identifiers */
695         ot->name = "Copy To Selected";
696         ot->idname = "UI_OT_copy_to_selected_button";
697         ot->description = "Copy property from this object to selected objects or bones";
698
699         /* callbacks */
700         ot->poll = copy_to_selected_button_poll;
701         ot->exec = copy_to_selected_button_exec;
702
703         /* flags */
704         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
705
706         /* properties */
707         RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
708 }
709
710 /* Reports to Textblock Operator ------------------------ */
711
712 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere 
713  * when there are too many to display...
714  */
715
716 static int reports_to_text_poll(bContext *C)
717 {
718         return CTX_wm_reports(C) != NULL;
719 }
720
721 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
722 {
723         ReportList *reports = CTX_wm_reports(C);
724         Main *bmain = CTX_data_main(C);
725         Text *txt;
726         char *str;
727         
728         /* create new text-block to write to */
729         txt = BKE_text_add(bmain, "Recent Reports");
730         
731         /* convert entire list to a display string, and add this to the text-block
732          *      - if commandline debug option enabled, show debug reports too
733          *      - otherwise, up to info (which is what users normally see)
734          */
735         str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
736
737         if (str) {
738                 BKE_text_write(txt, str);
739                 MEM_freeN(str);
740
741                 return OPERATOR_FINISHED;
742         }
743         else {
744                 return OPERATOR_CANCELLED;
745         }
746 }
747
748 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
749 {
750         /* identifiers */
751         ot->name = "Reports to Text Block";
752         ot->idname = "UI_OT_reports_to_textblock";
753         ot->description = "Write the reports ";
754         
755         /* callbacks */
756         ot->poll = reports_to_text_poll;
757         ot->exec = reports_to_text_exec;
758 }
759
760 #ifdef WITH_PYTHON
761
762 /* ------------------------------------------------------------------------- */
763 /* EditSource Utility funcs and operator,
764  * note, this includes utility functions and button matching checks */
765
766 typedef struct uiEditSourceStore {
767         uiBut but_orig;
768         GHash *hash;
769 } uiEditSourceStore;
770
771 typedef struct uiEditSourceButStore {
772         char py_dbg_fn[FILE_MAX];
773         int py_dbg_ln;
774 } uiEditSourceButStore;
775
776 /* should only ever be set while the edit source operator is running */
777 static struct uiEditSourceStore *ui_editsource_info = NULL;
778
779 bool UI_editsource_enable_check(void)
780 {
781         return (ui_editsource_info != NULL);
782 }
783
784 static void ui_editsource_active_but_set(uiBut *but)
785 {
786         BLI_assert(ui_editsource_info == NULL);
787
788         ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__);
789         memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut));
790
791         ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
792 }
793
794 static void ui_editsource_active_but_clear(void)
795 {
796         BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN);
797         MEM_freeN(ui_editsource_info);
798         ui_editsource_info = NULL;
799 }
800
801 static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
802 {
803 #if 0
804         printf("matching buttons: '%s' == '%s'\n",
805                but_a->drawstr, but_b->drawstr);
806 #endif
807
808         /* this just needs to be a 'good-enough' comparison so we can know beyond
809          * reasonable doubt that these buttons are the same between redraws.
810          * if this fails it only means edit-source fails - campbell */
811         if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) &&
812             (but_a->type == but_b->type) &&
813             (but_a->rnaprop == but_b->rnaprop) &&
814             (but_a->optype == but_b->optype) &&
815             (but_a->unit_type == but_b->unit_type) &&
816             STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR))
817         {
818                 return true;
819         }
820         else {
821                 return false;
822         }
823 }
824
825 void UI_editsource_active_but_test(uiBut *but)
826 {
827         extern void PyC_FileAndNum_Safe(const char **filename, int *lineno);
828
829         struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__);
830
831         const char *fn;
832         int lineno = -1;
833
834 #if 0
835         printf("comparing buttons: '%s' == '%s'\n",
836                but->drawstr, ui_editsource_info->but_orig.drawstr);
837 #endif
838
839         PyC_FileAndNum_Safe(&fn, &lineno);
840
841         if (lineno != -1) {
842                 BLI_strncpy(but_store->py_dbg_fn, fn,
843                             sizeof(but_store->py_dbg_fn));
844                 but_store->py_dbg_ln = lineno;
845         }
846         else {
847                 but_store->py_dbg_fn[0] = '\0';
848                 but_store->py_dbg_ln = -1;
849         }
850
851         BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
852 }
853
854 static int editsource_text_edit(
855         bContext *C, wmOperator *op,
856         char filepath[FILE_MAX], int line)
857 {
858         struct Main *bmain = CTX_data_main(C);
859         Text *text;
860
861         for (text = bmain->text.first; text; text = text->id.next) {
862                 if (text->name && BLI_path_cmp(text->name, filepath) == 0) {
863                         break;
864                 }
865         }
866
867         if (text == NULL) {
868                 text = BKE_text_load(bmain, filepath, bmain->name);
869                 id_us_ensure_real(&text->id);
870         }
871
872         if (text == NULL) {
873                 BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
874                 return OPERATOR_CANCELLED;
875         }
876         else {
877                 /* naughty!, find text area to set, not good behavior
878                  * but since this is a dev tool lets allow it - campbell */
879                 ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
880                 if (sa) {
881                         SpaceText *st = sa->spacedata.first;
882                         st->text = text;
883                 }
884                 else {
885                         BKE_reportf(op->reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2);
886                 }
887
888                 txt_move_toline(text, line - 1, false);
889                 WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, text);
890         }
891
892         return OPERATOR_FINISHED;
893 }
894
895 static int editsource_exec(bContext *C, wmOperator *op)
896 {
897         uiBut *but = UI_context_active_but_get(C);
898
899         if (but) {
900                 GHashIterator ghi;
901                 struct uiEditSourceButStore *but_store = NULL;
902
903                 ARegion *ar = CTX_wm_region(C);
904                 int ret;
905
906                 /* needed else the active button does not get tested */
907                 UI_screen_free_active_but(C, CTX_wm_screen(C));
908
909                 // printf("%s: begin\n", __func__);
910
911                 /* take care not to return before calling ui_editsource_active_but_clear */
912                 ui_editsource_active_but_set(but);
913
914                 /* redraw and get active button python info */
915                 ED_region_do_draw(C, ar);
916                 ar->do_draw = false;
917
918                 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
919                      BLI_ghashIterator_done(&ghi) == false;
920                      BLI_ghashIterator_step(&ghi))
921                 {
922                         uiBut *but_key = BLI_ghashIterator_getKey(&ghi);
923                         if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
924                                 but_store = BLI_ghashIterator_getValue(&ghi);
925                                 break;
926                         }
927
928                 }
929
930                 if (but_store) {
931                         if (but_store->py_dbg_ln != -1) {
932                                 ret = editsource_text_edit(C, op,
933                                                            but_store->py_dbg_fn,
934                                                            but_store->py_dbg_ln);
935                         }
936                         else {
937                                 BKE_report(op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
938                                 ret = OPERATOR_CANCELLED;
939                         }
940                 }
941                 else {
942                         BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
943                         ret = OPERATOR_CANCELLED;
944                 }
945
946
947                 ui_editsource_active_but_clear();
948
949                 // printf("%s: end\n", __func__);
950
951                 return ret;
952         }
953         else {
954                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
955                 return OPERATOR_CANCELLED;
956         }
957 }
958
959 static void UI_OT_editsource(wmOperatorType *ot)
960 {
961         /* identifiers */
962         ot->name = "Edit Source";
963         ot->idname = "UI_OT_editsource";
964         ot->description = "Edit UI source code of the active button";
965
966         /* callbacks */
967         ot->exec = editsource_exec;
968 }
969
970 /* ------------------------------------------------------------------------- */
971
972 /**
973  * EditTranslation utility funcs and operator,
974  * \note: this includes utility functions and button matching checks.
975  * this only works in conjunction with a py operator!
976  */
977 static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
978 {
979         char tstr[32]; /* Should be more than enough! */
980
981         /* First, full lang code. */
982         BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
983         BLI_join_dirfile(path, maxlen, root, uilng);
984         BLI_path_append(path, maxlen, tstr);
985         if (BLI_is_file(path))
986                 return;
987
988         /* Now try without the second iso code part (_ES in es_ES). */
989         {
990                 const char *tc = NULL;
991                 size_t szt = 0;
992                 tstr[0] = '\0';
993
994                 tc = strchr(uilng, '_');
995                 if (tc) {
996                         szt = tc - uilng;
997                         if (szt < sizeof(tstr)) /* Paranoid, should always be true! */
998                                 BLI_strncpy(tstr, uilng, szt + 1); /* +1 for '\0' char! */
999                 }
1000                 if (tstr[0]) {
1001                         /* Because of some codes like sr_SR@latin... */
1002                         tc = strchr(uilng, '@');
1003                         if (tc)
1004                                 BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
1005
1006                         BLI_join_dirfile(path, maxlen, root, tstr);
1007                         strcat(tstr, ".po");
1008                         BLI_path_append(path, maxlen, tstr);
1009                         if (BLI_is_file(path))
1010                                 return;
1011                 }
1012         }
1013
1014         /* Else no po file! */
1015         path[0] = '\0';
1016 }
1017
1018 static int edittranslation_exec(bContext *C, wmOperator *op)
1019 {
1020         uiBut *but = UI_context_active_but_get(C);
1021         int ret = OPERATOR_CANCELLED;
1022
1023         if (but) {
1024                 wmOperatorType *ot;
1025                 PointerRNA ptr;
1026                 char popath[FILE_MAX];
1027                 const char *root = U.i18ndir;
1028                 const char *uilng = BLT_lang_get();
1029
1030                 uiStringInfo but_label = {BUT_GET_LABEL, NULL};
1031                 uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
1032                 uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
1033                 uiStringInfo but_tip = {BUT_GET_TIP, NULL};
1034                 uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL};
1035                 uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
1036                 uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
1037                 uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
1038                 uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL};
1039                 uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL};
1040
1041                 if (!BLI_is_dir(root)) {
1042                         BKE_report(op->reports, RPT_ERROR, "Please set your User Preferences' 'Translation Branches "
1043                                                            "Directory' path to a valid directory");
1044                         return OPERATOR_CANCELLED;
1045                 }
1046                 ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
1047                 if (ot == NULL) {
1048                         BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate add-on "
1049                                                             "in the User Preferences", EDTSRC_I18N_OP_NAME);
1050                         return OPERATOR_CANCELLED;
1051                 }
1052                 /* Try to find a valid po file for current language... */
1053                 edittranslation_find_po_file(root, uilng, popath, FILE_MAX);
1054 /*              printf("po path: %s\n", popath);*/
1055                 if (popath[0] == '\0') {
1056                         BKE_reportf(op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root);
1057                         return OPERATOR_CANCELLED;
1058                 }
1059
1060                 UI_but_string_info_get(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
1061                                 &rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);
1062
1063                 WM_operator_properties_create_ptr(&ptr, ot);
1064                 RNA_string_set(&ptr, "lang", uilng);
1065                 RNA_string_set(&ptr, "po_file", popath);
1066                 RNA_string_set(&ptr, "but_label", but_label.strinfo);
1067                 RNA_string_set(&ptr, "rna_label", rna_label.strinfo);
1068                 RNA_string_set(&ptr, "enum_label", enum_label.strinfo);
1069                 RNA_string_set(&ptr, "but_tip", but_tip.strinfo);
1070                 RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo);
1071                 RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo);
1072                 RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo);
1073                 RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
1074                 RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
1075                 RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
1076                 ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
1077
1078                 /* Clean up */
1079                 if (but_label.strinfo)
1080                         MEM_freeN(but_label.strinfo);
1081                 if (rna_label.strinfo)
1082                         MEM_freeN(rna_label.strinfo);
1083                 if (enum_label.strinfo)
1084                         MEM_freeN(enum_label.strinfo);
1085                 if (but_tip.strinfo)
1086                         MEM_freeN(but_tip.strinfo);
1087                 if (rna_tip.strinfo)
1088                         MEM_freeN(rna_tip.strinfo);
1089                 if (enum_tip.strinfo)
1090                         MEM_freeN(enum_tip.strinfo);
1091                 if (rna_struct.strinfo)
1092                         MEM_freeN(rna_struct.strinfo);
1093                 if (rna_prop.strinfo)
1094                         MEM_freeN(rna_prop.strinfo);
1095                 if (rna_enum.strinfo)
1096                         MEM_freeN(rna_enum.strinfo);
1097                 if (rna_ctxt.strinfo)
1098                         MEM_freeN(rna_ctxt.strinfo);
1099
1100                 return ret;
1101         }
1102         else {
1103                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
1104                 return OPERATOR_CANCELLED;
1105         }
1106 }
1107
1108 static void UI_OT_edittranslation_init(wmOperatorType *ot)
1109 {
1110         /* identifiers */
1111         ot->name = "Edit Translation";
1112         ot->idname = "UI_OT_edittranslation_init";
1113         ot->description = "Edit i18n in current language for the active button";
1114
1115         /* callbacks */
1116         ot->exec = edittranslation_exec;
1117 }
1118
1119 #endif /* WITH_PYTHON */
1120
1121 static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
1122 {
1123         BLT_lang_init();
1124         BLF_cache_clear();
1125         BLT_lang_set(NULL);
1126         UI_reinit_font();
1127         return OPERATOR_FINISHED;
1128 }
1129
1130 static void UI_OT_reloadtranslation(wmOperatorType *ot)
1131 {
1132         /* identifiers */
1133         ot->name = "Reload Translation";
1134         ot->idname = "UI_OT_reloadtranslation";
1135         ot->description = "Force a full reload of UI translation";
1136
1137         /* callbacks */
1138         ot->exec = reloadtranslation_exec;
1139 }
1140
1141 int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
1142 {
1143         /* should only return true for regions that include buttons, for now
1144          * return true always */
1145         if (drag->type == WM_DRAG_COLOR) {
1146                 SpaceImage *sima = CTX_wm_space_image(C);
1147                 ARegion *ar = CTX_wm_region(C);
1148
1149                 if (UI_but_active_drop_color(C))
1150                         return 1;
1151
1152                 if (sima && (sima->mode == SI_MODE_PAINT) &&
1153                     sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
1154                 {
1155                         return 1;
1156                 }
1157         }
1158
1159         return 0;
1160 }
1161
1162 void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
1163 {
1164         uiDragColorHandle *drag_info = drag->poin;
1165
1166         RNA_float_set_array(drop->ptr, "color", drag_info->color);
1167         RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
1168 }
1169
1170 static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1171 {
1172         ARegion *ar = CTX_wm_region(C);
1173         uiBut *but = NULL;
1174         float color[4];
1175         bool gamma;
1176
1177         RNA_float_get_array(op->ptr, "color", color);
1178         gamma = RNA_boolean_get(op->ptr, "gamma");
1179
1180         /* find button under mouse, check if it has RNA color property and
1181          * if it does copy the data */
1182         but = ui_but_find_active_in_region(ar);
1183
1184         if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
1185                 const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
1186                 BLI_assert(color_len <= 4);
1187
1188                 /* keep alpha channel as-is */
1189                 if (color_len == 4) {
1190                         color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
1191                 }
1192
1193                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
1194                         if (!gamma)
1195                                 ui_block_cm_to_display_space_v3(but->block, color);
1196                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
1197                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
1198                 }
1199                 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
1200                         if (gamma)
1201                                 ui_block_cm_to_scene_linear_v3(but->block, color);
1202                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
1203                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
1204                 }
1205         }
1206         else {
1207                 if (gamma) {
1208                         srgb_to_linearrgb_v3_v3(color, color);
1209                 }
1210
1211                 ED_imapaint_bucket_fill(C, color, op);
1212         }
1213
1214         ED_region_tag_redraw(ar);
1215
1216         return OPERATOR_FINISHED;
1217 }
1218
1219
1220 static void UI_OT_drop_color(wmOperatorType *ot)
1221 {
1222         ot->name = "Drop Color";
1223         ot->idname = "UI_OT_drop_color";
1224         ot->description = "Drop colors to buttons";
1225
1226         ot->invoke = drop_color_invoke;
1227         ot->flag = OPTYPE_INTERNAL;
1228
1229         RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
1230         RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
1231 }
1232
1233
1234 /* ********************************************************* */
1235 /* Registration */
1236
1237 void ED_operatortypes_ui(void)
1238 {
1239         WM_operatortype_append(UI_OT_reset_default_theme);
1240         WM_operatortype_append(UI_OT_copy_data_path_button);
1241         WM_operatortype_append(UI_OT_copy_python_command_button);
1242         WM_operatortype_append(UI_OT_reset_default_button);
1243         WM_operatortype_append(UI_OT_unset_property_button);
1244         WM_operatortype_append(UI_OT_use_property_button);
1245         WM_operatortype_append(UI_OT_unuse_property_button);
1246         WM_operatortype_append(UI_OT_copy_to_selected_button);
1247         WM_operatortype_append(UI_OT_reports_to_textblock);  /* XXX: temp? */
1248         WM_operatortype_append(UI_OT_drop_color);
1249 #ifdef WITH_PYTHON
1250         WM_operatortype_append(UI_OT_editsource);
1251         WM_operatortype_append(UI_OT_edittranslation_init);
1252 #endif
1253         WM_operatortype_append(UI_OT_reloadtranslation);
1254
1255         /* external */
1256         WM_operatortype_append(UI_OT_eyedropper_color);
1257         WM_operatortype_append(UI_OT_eyedropper_id);
1258         WM_operatortype_append(UI_OT_eyedropper_depth);
1259         WM_operatortype_append(UI_OT_eyedropper_driver);
1260 }
1261
1262 /**
1263  * \brief User Interface Keymap
1264  */
1265 void ED_keymap_ui(wmKeyConfig *keyconf)
1266 {
1267         wmKeyMap *keymap = WM_keymap_find(keyconf, "User Interface", 0, 0);
1268         wmKeyMapItem *kmi;
1269
1270         /* eyedroppers - notice they all have the same shortcut, but pass the event
1271          * through until a suitable eyedropper for the active button is found */
1272         WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0);
1273         WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
1274         WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
1275
1276         /* Copy Data Path */
1277         WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
1278         kmi = WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
1279         RNA_boolean_set(kmi->ptr, "full_path", true);
1280
1281         /* keyframes */
1282         WM_keymap_add_item(keymap, "ANIM_OT_keyframe_insert_button", IKEY, KM_PRESS, 0, 0);
1283         WM_keymap_add_item(keymap, "ANIM_OT_keyframe_delete_button", IKEY, KM_PRESS, KM_ALT, 0);
1284         WM_keymap_add_item(keymap, "ANIM_OT_keyframe_clear_button", IKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0);
1285
1286         /* drivers */
1287         WM_keymap_add_item(keymap, "ANIM_OT_driver_button_add", DKEY, KM_PRESS, KM_CTRL, 0);
1288         WM_keymap_add_item(keymap, "ANIM_OT_driver_button_remove", DKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
1289
1290         /* keyingsets */
1291         WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_add", KKEY, KM_PRESS, 0, 0);
1292         WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0);
1293
1294         eyedropper_modal_keymap(keyconf);
1295 }