doxygen: add newline after \file
[blender.git] / source / blender / editors / interface / interface_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edinterface
22  */
23
24 #include <string.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "DNA_armature_types.h"
29 #include "DNA_screen_types.h"
30 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
31 #include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */
32
33 #include "BLI_blenlib.h"
34 #include "BLI_math_color.h"
35
36 #include "BLF_api.h"
37 #include "BLT_lang.h"
38
39 #include "BKE_context.h"
40 #include "BKE_global.h"
41 #include "BKE_idprop.h"
42 #include "BKE_layer.h"
43 #include "BKE_library.h"
44 #include "BKE_library_override.h"
45 #include "BKE_node.h"
46 #include "BKE_report.h"
47 #include "BKE_screen.h"
48 #include "BKE_text.h" /* for UI_OT_reports_to_text */
49
50 #include "IMB_colormanagement.h"
51
52 #include "DEG_depsgraph.h"
53
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 #include "RNA_types.h"
57
58 #include "UI_interface.h"
59
60 #include "interface_intern.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_object.h"
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 bool 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 bool 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 bool 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 /* Assign Value as Default Button Operator ------------------------ */
299
300 static bool assign_default_button_poll(bContext *C)
301 {
302         PointerRNA ptr;
303         PropertyRNA *prop;
304         int index;
305
306         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
307
308         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
309                 PropertyType type = RNA_property_type(prop);
310
311                 return RNA_property_is_idprop(prop) && !RNA_property_array_check(prop) && ELEM(type, PROP_INT, PROP_FLOAT);
312         }
313
314         return false;
315 }
316
317 static int assign_default_button_exec(bContext *C, wmOperator *UNUSED(op))
318 {
319         PointerRNA ptr;
320         PropertyRNA *prop;
321         int index;
322
323         /* try to reset the nominated setting to its default value */
324         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
325
326         /* if there is a valid property that is editable... */
327         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
328                 if (RNA_property_assign_default(&ptr, prop))
329                         return operator_button_property_finish(C, &ptr, prop);
330         }
331
332         return OPERATOR_CANCELLED;
333 }
334
335 static void UI_OT_assign_default_button(wmOperatorType *ot)
336 {
337         /* identifiers */
338         ot->name = "Assign Value as Default";
339         ot->idname = "UI_OT_assign_default_button";
340         ot->description = "Set this property's current value as the new default";
341
342         /* callbacks */
343         ot->poll = assign_default_button_poll;
344         ot->exec = assign_default_button_exec;
345
346         /* flags */
347         ot->flag = OPTYPE_UNDO;
348 }
349
350 /* Unset Property Button Operator ------------------------ */
351
352 static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
353 {
354         PointerRNA ptr;
355         PropertyRNA *prop;
356         int index;
357
358         /* try to unset the nominated property */
359         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
360
361         /* if there is a valid property that is editable... */
362         if (ptr.data && prop && RNA_property_editable(&ptr, prop) &&
363             /* RNA_property_is_idprop(prop) && */
364             RNA_property_is_set(&ptr, prop))
365         {
366                 RNA_property_unset(&ptr, prop);
367                 return operator_button_property_finish(C, &ptr, prop);
368         }
369
370         return OPERATOR_CANCELLED;
371 }
372
373 static void UI_OT_unset_property_button(wmOperatorType *ot)
374 {
375         /* identifiers */
376         ot->name = "Unset property";
377         ot->idname = "UI_OT_unset_property_button";
378         ot->description = "Clear the property and use default or generated value in operators";
379
380         /* callbacks */
381         ot->poll = ED_operator_regionactive;
382         ot->exec = unset_property_button_exec;
383
384         /* flags */
385         ot->flag = OPTYPE_UNDO;
386 }
387
388
389 /* Note that we use different values for UI/UX than 'real' override operations, user does not care
390  * whether it's added or removed for the differential operation e.g. */
391 enum {
392         UIOverride_Type_NOOP = 0,
393         UIOverride_Type_Replace = 1,
394         UIOverride_Type_Difference = 2,  /* Add/subtract */
395         UIOverride_Type_Factor = 3,  /* Multiply */
396         /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
397 };
398
399 static EnumPropertyItem override_type_items[] = {
400         {UIOverride_Type_NOOP, "NOOP", 0, "NoOp",
401          "'No-Operation', place holder preventing automatic override to ever affect the property"},
402         {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"},
403         {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"},
404         {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"},
405         {0, NULL, 0, NULL, NULL},
406 };
407
408
409 static bool override_type_set_button_poll(bContext *C)
410 {
411         PointerRNA ptr;
412         PropertyRNA *prop;
413         int index;
414
415         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
416
417         const int override_status = RNA_property_static_override_status(&ptr, prop, index);
418
419         return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
420 }
421
422 static int override_type_set_button_exec(bContext *C, wmOperator *op)
423 {
424         PointerRNA ptr;
425         PropertyRNA *prop;
426         int index;
427         bool created;
428         const bool all = RNA_boolean_get(op->ptr, "all");
429         const int op_type = RNA_enum_get(op->ptr, "type");
430
431         short operation;
432
433         switch (op_type) {
434                 case UIOverride_Type_NOOP:
435                         operation = IDOVERRIDESTATIC_OP_NOOP;
436                         break;
437                 case UIOverride_Type_Replace:
438                         operation = IDOVERRIDESTATIC_OP_REPLACE;
439                         break;
440                 case UIOverride_Type_Difference:
441                         /* override code will automatically switch to subtract if needed. */
442                         operation = IDOVERRIDESTATIC_OP_ADD;
443                         break;
444                 case UIOverride_Type_Factor:
445                         operation = IDOVERRIDESTATIC_OP_MULTIPLY;
446                         break;
447                 default:
448                         operation = IDOVERRIDESTATIC_OP_REPLACE;
449                         BLI_assert(0);
450                         break;
451         }
452
453         /* try to reset the nominated setting to its default value */
454         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
455
456         BLI_assert(ptr.id.data != NULL);
457
458         if (all) {
459                 index = -1;
460         }
461
462         IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get(
463                 &ptr, prop, operation, index, true, NULL, &created);
464         if (!created) {
465                 opop->operation = operation;
466         }
467
468         return operator_button_property_finish(C, &ptr, prop);
469 }
470
471 static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
472 {
473 #if 0  /* Disabled for now */
474         return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
475 #else
476         RNA_enum_set(op->ptr, "type", IDOVERRIDESTATIC_OP_REPLACE);
477         return override_type_set_button_exec(C, op);
478 #endif
479 }
480
481 static void UI_OT_override_type_set_button(wmOperatorType *ot)
482 {
483         /* identifiers */
484         ot->name = "Define Override Type";
485         ot->idname = "UI_OT_override_type_set_button";
486         ot->description = "Create an override operation, or set the type of an existing one";
487
488         /* callbacks */
489         ot->poll = override_type_set_button_poll;
490         ot->exec = override_type_set_button_exec;
491         ot->invoke = override_type_set_button_invoke;
492
493         /* flags */
494         ot->flag = OPTYPE_UNDO;
495
496         /* properties */
497         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
498         ot->prop = RNA_def_enum(
499                 ot->srna, "type", override_type_items, UIOverride_Type_Replace,
500                 "Type", "Type of override operation");
501         /* TODO: add itemf callback, not all options are available for all data types... */
502 }
503
504
505 static bool override_remove_button_poll(bContext *C)
506 {
507         PointerRNA ptr;
508         PropertyRNA *prop;
509         int index;
510
511         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
512
513         const int override_status = RNA_property_static_override_status(&ptr, prop, index);
514
515         return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
516 }
517
518 static int override_remove_button_exec(bContext *C, wmOperator *op)
519 {
520         Main *bmain = CTX_data_main(C);
521         PointerRNA ptr, id_refptr, src;
522         PropertyRNA *prop;
523         int index;
524         const bool all = RNA_boolean_get(op->ptr, "all");
525
526         /* try to reset the nominated setting to its default value */
527         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
528
529         ID *id = ptr.id.data;
530         IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop);
531         BLI_assert(oprop != NULL);
532         BLI_assert(id != NULL && id->override_static != NULL);
533
534         const bool is_template = (id->override_static->reference == NULL);
535
536         /* We need source (i.e. linked data) to restore values of deleted overrides...
537          * If this is an override template, we obviously do not need to restore anything. */
538         if (!is_template) {
539                 RNA_id_pointer_create(id->override_static->reference, &id_refptr);
540                 if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) {
541                         BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
542                 }
543         }
544
545         if (!all && index != -1) {
546                 bool is_strict_find;
547                 /* Remove override operation for given item,
548                  * add singular operations for the other items as needed. */
549                 IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
550                         oprop, NULL, NULL, index, index, false, &is_strict_find);
551                 BLI_assert(opop != NULL);
552                 if (!is_strict_find) {
553                         /* No specific override operation, we have to get generic one,
554                          * and create item-specific override operations for all but given index,
555                          * before removing generic one. */
556                         for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) {
557                                 if (idx != index) {
558                                         BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
559                                 }
560                         }
561                 }
562                 BKE_override_static_property_operation_delete(oprop, opop);
563                 if (!is_template) {
564                         RNA_property_copy(bmain, &ptr, &src, prop, index);
565                 }
566                 if (BLI_listbase_is_empty(&oprop->operations)) {
567                         BKE_override_static_property_delete(id->override_static, oprop);
568                 }
569         }
570         else {
571                 /* Just remove whole generic override operation of this property. */
572                 BKE_override_static_property_delete(id->override_static, oprop);
573                 if (!is_template) {
574                         RNA_property_copy(bmain, &ptr, &src, prop, -1);
575                 }
576         }
577
578         return operator_button_property_finish(C, &ptr, prop);
579 }
580
581 static void UI_OT_override_remove_button(wmOperatorType *ot)
582 {
583         /* identifiers */
584         ot->name = "Remove Override";
585         ot->idname = "UI_OT_override_remove_button";
586         ot->description = "Remove an override operation";
587
588         /* callbacks */
589         ot->poll = override_remove_button_poll;
590         ot->exec = override_remove_button_exec;
591
592         /* flags */
593         ot->flag = OPTYPE_UNDO;
594
595         /* properties */
596         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
597 }
598
599
600
601
602 /* Copy To Selected Operator ------------------------ */
603
604 bool UI_context_copy_to_selected_list(
605         bContext *C, PointerRNA *ptr, PropertyRNA *prop,
606         ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
607 {
608         *r_use_path_from_id = false;
609         *r_path = NULL;
610
611         if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
612                 *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
613         }
614         else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
615                 *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
616         }
617         else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) {
618                 ListBase lb;
619                 lb = CTX_data_collection_get(C, "selected_pose_bones");
620
621                 if (!BLI_listbase_is_empty(&lb)) {
622                         CollectionPointerLink *link;
623                         for (link = lb.first; link; link = link->next) {
624                                 bPoseChannel *pchan = link->ptr.data;
625                                 RNA_pointer_create(link->ptr.id.data, &RNA_Bone, pchan->bone, &link->ptr);
626                         }
627                 }
628
629                 *r_lb = lb;
630         }
631         else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
632                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
633         }
634         else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
635                 *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
636         }
637         else if (RNA_struct_is_a(ptr->type, &RNA_Node) ||
638                  RNA_struct_is_a(ptr->type, &RNA_NodeSocket))
639         {
640                 ListBase lb = {NULL, NULL};
641                 char *path = NULL;
642                 bNode *node = NULL;
643
644                 /* Get the node we're editing */
645                 if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
646                         bNodeTree *ntree = ptr->id.data;
647                         bNodeSocket *sock = ptr->data;
648                         if (nodeFindNode(ntree, sock, &node, NULL)) {
649                                 if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) {
650                                         /* we're good! */
651                                 }
652                                 else {
653                                         node = NULL;
654                                 }
655                         }
656                 }
657                 else {
658                         node = ptr->data;
659                 }
660
661                 /* Now filter by type */
662                 if (node) {
663                         CollectionPointerLink *link, *link_next;
664                         lb = CTX_data_collection_get(C, "selected_nodes");
665
666                         for (link = lb.first; link; link = link_next) {
667                                 bNode *node_data = link->ptr.data;
668                                 link_next = link->next;
669
670                                 if (node_data->type != node->type) {
671                                         BLI_remlink(&lb, link);
672                                         MEM_freeN(link);
673                                 }
674                         }
675                 }
676
677                 *r_lb = lb;
678                 *r_path = path;
679         }
680         else if (ptr->id.data) {
681                 ID *id = ptr->id.data;
682
683                 if (GS(id->name) == ID_OB) {
684                         *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
685                         *r_use_path_from_id = true;
686                         *r_path = RNA_path_from_ID_to_property(ptr, prop);
687                 }
688                 else if (OB_DATA_SUPPORT_ID(GS(id->name))) {
689                         /* check we're using the active object */
690                         const short id_code = GS(id->name);
691                         ListBase lb = CTX_data_collection_get(C, "selected_editable_objects");
692                         char *path = RNA_path_from_ID_to_property(ptr, prop);
693
694                         /* de-duplicate obdata */
695                         if (!BLI_listbase_is_empty(&lb)) {
696                                 CollectionPointerLink *link, *link_next;
697
698                                 for (link = lb.first; link; link = link->next) {
699                                         Object *ob = link->ptr.id.data;
700                                         if (ob->data) {
701                                                 ID *id_data = ob->data;
702                                                 id_data->tag |= LIB_TAG_DOIT;
703                                         }
704                                 }
705
706                                 for (link = lb.first; link; link = link_next) {
707                                         Object *ob = link->ptr.id.data;
708                                         ID *id_data = ob->data;
709                                         link_next = link->next;
710
711                                         if ((id_data == NULL) ||
712                                             (id_data->tag & LIB_TAG_DOIT) == 0 ||
713                                             ID_IS_LINKED(id_data) ||
714                                             (GS(id_data->name) != id_code))
715                                         {
716                                                 BLI_remlink(&lb, link);
717                                                 MEM_freeN(link);
718                                         }
719                                         else {
720                                                 /* avoid prepending 'data' to the path */
721                                                 RNA_id_pointer_create(id_data, &link->ptr);
722                                         }
723
724                                         if (id_data) {
725                                                 id_data->tag &= ~LIB_TAG_DOIT;
726                                         }
727                                 }
728                         }
729
730                         *r_lb = lb;
731                         *r_path = path;
732                 }
733                 else if (GS(id->name) == ID_SCE) {
734                         /* Sequencer's ID is scene :/ */
735                         /* Try to recursively find an RNA_Sequence ancestor,
736                          * to handle situations like T41062... */
737                         if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
738                                 *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
739                         }
740                 }
741                 return (*r_path != NULL);
742         }
743         else {
744                 return false;
745         }
746
747         return true;
748 }
749
750 /**
751  * called from both exec & poll
752  *
753  * \note: normally we wouldn't call a loop from within a poll function,
754  * However this is a special case, and for regular poll calls, getting
755  * the context from the button will fail early.
756  */
757 static bool copy_to_selected_button(bContext *C, bool all, bool poll)
758 {
759         Main *bmain = CTX_data_main(C);
760         PointerRNA ptr, lptr, idptr;
761         PropertyRNA *prop, *lprop;
762         bool success = false;
763         int index;
764
765         /* try to reset the nominated setting to its default value */
766         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
767
768         /* if there is a valid property that is editable... */
769         if (ptr.data && prop) {
770                 char *path = NULL;
771                 bool use_path_from_id;
772                 CollectionPointerLink *link;
773                 ListBase lb = {NULL};
774
775                 if (UI_context_copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path) &&
776                     !BLI_listbase_is_empty(&lb))
777                 {
778                         for (link = lb.first; link; link = link->next) {
779                                 if (link->ptr.data != ptr.data) {
780                                         if (use_path_from_id) {
781                                                 /* Path relative to ID. */
782                                                 lprop = NULL;
783                                                 RNA_id_pointer_create(link->ptr.id.data, &idptr);
784                                                 RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
785                                         }
786                                         else if (path) {
787                                                 /* Path relative to elements from list. */
788                                                 lprop = NULL;
789                                                 RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
790                                         }
791                                         else {
792                                                 lptr = link->ptr;
793                                                 lprop = prop;
794                                         }
795
796                                         if (lptr.data == ptr.data) {
797                                                 /* lptr might not be the same as link->ptr! */
798                                                 continue;
799                                         }
800
801                                         if (lprop == prop) {
802                                                 if (RNA_property_editable(&lptr, lprop)) {
803                                                         if (poll) {
804                                                                 success = true;
805                                                                 break;
806                                                         }
807                                                         else {
808                                                                 if (RNA_property_copy(bmain, &lptr, &ptr, prop, (all) ? -1 : index)) {
809                                                                         RNA_property_update(C, &lptr, prop);
810                                                                         success = true;
811                                                                 }
812                                                         }
813                                                 }
814                                         }
815                                 }
816                         }
817                 }
818                 MEM_SAFE_FREE(path);
819                 BLI_freelistN(&lb);
820         }
821
822         return success;
823 }
824
825 static bool copy_to_selected_button_poll(bContext *C)
826 {
827         return copy_to_selected_button(C, false, true);
828 }
829
830 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
831 {
832         bool success;
833
834         const bool all = RNA_boolean_get(op->ptr, "all");
835
836         success = copy_to_selected_button(C, all, false);
837
838         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
839 }
840
841 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
842 {
843         /* identifiers */
844         ot->name = "Copy To Selected";
845         ot->idname = "UI_OT_copy_to_selected_button";
846         ot->description = "Copy property from this object to selected objects or bones";
847
848         /* callbacks */
849         ot->poll = copy_to_selected_button_poll;
850         ot->exec = copy_to_selected_button_exec;
851
852         /* flags */
853         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
854
855         /* properties */
856         RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
857 }
858
859
860 /* -------------------------------------------------------------------- */
861 /** \name Jump to Target Operator
862  * \{ */
863
864 /** Jump to the object or bone referenced by the pointer, or check if it is possible. */
865 static bool jump_to_target_ptr(bContext *C, PointerRNA ptr, const bool poll)
866 {
867         if (RNA_pointer_is_null(&ptr)) {
868                 return false;
869         }
870
871         /* Verify pointer type. */
872         char bone_name[MAXBONENAME];
873         const StructRNA *target_type = NULL;
874
875         if (ELEM(ptr.type, &RNA_EditBone, &RNA_PoseBone, &RNA_Bone)) {
876                 RNA_string_get(&ptr, "name", bone_name);
877                 if (bone_name[0] != '\0') {
878                         target_type = &RNA_Bone;
879                 }
880         }
881         else if (RNA_struct_is_a(ptr.type, &RNA_Object)) {
882                 target_type = &RNA_Object;
883         }
884
885         if (target_type == NULL) {
886                 return false;
887         }
888
889         /* Find the containing Object. */
890         ViewLayer *view_layer = CTX_data_view_layer(C);
891         Base *base = NULL;
892         const short id_type = GS(((ID *)ptr.id.data)->name);
893         if (id_type == ID_OB) {
894                 base = BKE_view_layer_base_find(view_layer, ptr.id.data);
895         }
896         else if (OB_DATA_SUPPORT_ID(id_type)) {
897                 base = ED_object_find_first_by_data_id(view_layer, ptr.id.data);
898         }
899
900         bool ok = false;
901         if ((base == NULL) ||
902             ((target_type == &RNA_Bone) && (base->object->type != OB_ARMATURE)))
903         {
904                 /* pass */
905         }
906         else if (poll) {
907                 ok = true;
908         }
909         else {
910                 /* Make optional. */
911                 const bool reveal_hidden = true;
912                 /* Select and activate the target. */
913                 if (target_type == &RNA_Bone) {
914                         ok = ED_object_jump_to_bone(C, base->object, bone_name, reveal_hidden);
915                 }
916                 else if (target_type == &RNA_Object) {
917                         ok = ED_object_jump_to_object(C, base->object, reveal_hidden);
918                 }
919                 else {
920                         BLI_assert(0);
921                 }
922         }
923         return ok;
924 }
925
926 /**
927  * Jump to the object or bone referred to by the current UI field value.
928  *
929  * \note quite heavy for a poll callback, but the operator is only
930  * used as a right click menu item for certain UI field types, and
931  * this will fail quickly if the context is completely unsuitable.
932  */
933 static bool jump_to_target_button(bContext *C, bool poll)
934 {
935         PointerRNA ptr, target_ptr;
936         PropertyRNA *prop;
937         int index;
938
939         UI_context_active_but_prop_get(C, &ptr, &prop, &index);
940
941         /* If there is a valid property... */
942         if (ptr.data && prop) {
943                 const PropertyType type = RNA_property_type(prop);
944
945                 /* For pointer properties, use their value directly. */
946                 if (type == PROP_POINTER) {
947                         target_ptr = RNA_property_pointer_get(&ptr, prop);
948
949                         return jump_to_target_ptr(C, target_ptr, poll);
950                 }
951                 /* For string properties with prop_search, look up the search collection item. */
952                 else if (type == PROP_STRING) {
953                         const uiBut *but = UI_context_active_but_get(C);
954
955                         if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) {
956                                 uiRNACollectionSearch *coll_search = but->search_arg;
957
958                                 char str_buf[MAXBONENAME];
959                                 char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
960
961                                 int found = RNA_property_collection_lookup_string(&coll_search->search_ptr, coll_search->search_prop, str_ptr, &target_ptr);
962
963                                 if (str_ptr != str_buf) {
964                                         MEM_freeN(str_ptr);
965                                 }
966
967                                 if (found) {
968                                         return jump_to_target_ptr(C, target_ptr, poll);
969                                 }
970                         }
971                 }
972         }
973
974         return false;
975 }
976
977 static bool jump_to_target_button_poll(bContext *C)
978 {
979         return jump_to_target_button(C, true);
980 }
981
982 static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
983 {
984         bool success = jump_to_target_button(C, false);
985
986         return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
987 }
988
989 static void UI_OT_jump_to_target_button(wmOperatorType *ot)
990 {
991         /* identifiers */
992         ot->name = "Jump To Target";
993         ot->idname = "UI_OT_jump_to_target_button";
994         ot->description = "Switch to the target object or bone";
995
996         /* callbacks */
997         ot->poll = jump_to_target_button_poll;
998         ot->exec = jump_to_target_button_exec;
999
1000         /* flags */
1001         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1002 }
1003
1004 /** \} */
1005
1006 /* Reports to Textblock Operator ------------------------ */
1007
1008 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere
1009  * when there are too many to display...
1010  */
1011
1012 static bool reports_to_text_poll(bContext *C)
1013 {
1014         return CTX_wm_reports(C) != NULL;
1015 }
1016
1017 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
1018 {
1019         ReportList *reports = CTX_wm_reports(C);
1020         Main *bmain = CTX_data_main(C);
1021         Text *txt;
1022         char *str;
1023
1024         /* create new text-block to write to */
1025         txt = BKE_text_add(bmain, "Recent Reports");
1026
1027         /* convert entire list to a display string, and add this to the text-block
1028          * - if commandline debug option enabled, show debug reports too
1029          * - otherwise, up to info (which is what users normally see)
1030          */
1031         str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO);
1032
1033         if (str) {
1034                 TextUndoBuf *utxt = NULL; // FIXME
1035                 BKE_text_write(txt, utxt, str);
1036                 MEM_freeN(str);
1037
1038                 return OPERATOR_FINISHED;
1039         }
1040         else {
1041                 return OPERATOR_CANCELLED;
1042         }
1043 }
1044
1045 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
1046 {
1047         /* identifiers */
1048         ot->name = "Reports to Text Block";
1049         ot->idname = "UI_OT_reports_to_textblock";
1050         ot->description = "Write the reports ";
1051
1052         /* callbacks */
1053         ot->poll = reports_to_text_poll;
1054         ot->exec = reports_to_text_exec;
1055 }
1056
1057 #ifdef WITH_PYTHON
1058
1059 /* ------------------------------------------------------------------------- */
1060 /* EditSource Utility funcs and operator,
1061  * note, this includes utility functions and button matching checks */
1062
1063 typedef struct uiEditSourceStore {
1064         uiBut but_orig;
1065         GHash *hash;
1066 } uiEditSourceStore;
1067
1068 typedef struct uiEditSourceButStore {
1069         char py_dbg_fn[FILE_MAX];
1070         int py_dbg_ln;
1071 } uiEditSourceButStore;
1072
1073 /* should only ever be set while the edit source operator is running */
1074 static struct uiEditSourceStore *ui_editsource_info = NULL;
1075
1076 bool UI_editsource_enable_check(void)
1077 {
1078         return (ui_editsource_info != NULL);
1079 }
1080
1081 static void ui_editsource_active_but_set(uiBut *but)
1082 {
1083         BLI_assert(ui_editsource_info == NULL);
1084
1085         ui_editsource_info = MEM_callocN(sizeof(uiEditSourceStore), __func__);
1086         memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut));
1087
1088         ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
1089 }
1090
1091 static void ui_editsource_active_but_clear(void)
1092 {
1093         BLI_ghash_free(ui_editsource_info->hash, NULL, MEM_freeN);
1094         MEM_freeN(ui_editsource_info);
1095         ui_editsource_info = NULL;
1096 }
1097
1098 static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
1099 {
1100 #if 0
1101         printf("matching buttons: '%s' == '%s'\n",
1102                but_a->drawstr, but_b->drawstr);
1103 #endif
1104
1105         /* this just needs to be a 'good-enough' comparison so we can know beyond
1106          * reasonable doubt that these buttons are the same between redraws.
1107          * if this fails it only means edit-source fails - campbell */
1108         if (BLI_rctf_compare(&but_a->rect, &but_b->rect, FLT_EPSILON) &&
1109             (but_a->type == but_b->type) &&
1110             (but_a->rnaprop == but_b->rnaprop) &&
1111             (but_a->optype == but_b->optype) &&
1112             (but_a->unit_type == but_b->unit_type) &&
1113             STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR))
1114         {
1115                 return true;
1116         }
1117         else {
1118                 return false;
1119         }
1120 }
1121
1122 void UI_editsource_active_but_test(uiBut *but)
1123 {
1124         extern void PyC_FileAndNum_Safe(const char **filename, int *lineno);
1125
1126         struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__);
1127
1128         const char *fn;
1129         int lineno = -1;
1130
1131 #if 0
1132         printf("comparing buttons: '%s' == '%s'\n",
1133                but->drawstr, ui_editsource_info->but_orig.drawstr);
1134 #endif
1135
1136         PyC_FileAndNum_Safe(&fn, &lineno);
1137
1138         if (lineno != -1) {
1139                 BLI_strncpy(but_store->py_dbg_fn, fn,
1140                             sizeof(but_store->py_dbg_fn));
1141                 but_store->py_dbg_ln = lineno;
1142         }
1143         else {
1144                 but_store->py_dbg_fn[0] = '\0';
1145                 but_store->py_dbg_ln = -1;
1146         }
1147
1148         BLI_ghash_insert(ui_editsource_info->hash, but, but_store);
1149 }
1150
1151 static int editsource_text_edit(
1152         bContext *C, wmOperator *op,
1153         const char filepath[FILE_MAX], const int line)
1154 {
1155         struct Main *bmain = CTX_data_main(C);
1156         Text *text;
1157
1158         /* Developers may wish to copy-paste to an external editor. */
1159         printf("%s:%d\n", filepath, line);
1160
1161         for (text = bmain->text.first; text; text = text->id.next) {
1162                 if (text->name && BLI_path_cmp(text->name, filepath) == 0) {
1163                         break;
1164                 }
1165         }
1166
1167         if (text == NULL) {
1168                 text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain));
1169                 id_us_ensure_real(&text->id);
1170         }
1171
1172         if (text == NULL) {
1173                 BKE_reportf(op->reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
1174                 return OPERATOR_CANCELLED;
1175         }
1176         else {
1177                 /* naughty!, find text area to set, not good behavior
1178                  * but since this is a dev tool lets allow it - campbell */
1179                 ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
1180                 if (sa) {
1181                         SpaceText *st = sa->spacedata.first;
1182                         st->text = text;
1183                 }
1184                 else {
1185                         BKE_reportf(op->reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2);
1186                 }
1187
1188                 txt_move_toline(text, line - 1, false);
1189                 WM_event_add_notifier(C, NC_TEXT | ND_CURSOR, text);
1190         }
1191
1192         return OPERATOR_FINISHED;
1193 }
1194
1195 static int editsource_exec(bContext *C, wmOperator *op)
1196 {
1197         uiBut *but = UI_context_active_but_get(C);
1198
1199         if (but) {
1200                 GHashIterator ghi;
1201                 struct uiEditSourceButStore *but_store = NULL;
1202
1203                 ARegion *ar = CTX_wm_region(C);
1204                 int ret;
1205
1206                 /* needed else the active button does not get tested */
1207                 UI_screen_free_active_but(C, CTX_wm_screen(C));
1208
1209                 // printf("%s: begin\n", __func__);
1210
1211                 /* take care not to return before calling ui_editsource_active_but_clear */
1212                 ui_editsource_active_but_set(but);
1213
1214                 /* redraw and get active button python info */
1215                 ED_region_do_layout(C, ar);
1216                 ED_region_do_draw(C, ar);
1217                 ar->do_draw = false;
1218
1219                 for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
1220                      BLI_ghashIterator_done(&ghi) == false;
1221                      BLI_ghashIterator_step(&ghi))
1222                 {
1223                         uiBut *but_key = BLI_ghashIterator_getKey(&ghi);
1224                         if (but_key && ui_editsource_uibut_match(&ui_editsource_info->but_orig, but_key)) {
1225                                 but_store = BLI_ghashIterator_getValue(&ghi);
1226                                 break;
1227                         }
1228
1229                 }
1230
1231                 if (but_store) {
1232                         if (but_store->py_dbg_ln != -1) {
1233                                 ret = editsource_text_edit(
1234                                         C, op,
1235                                         but_store->py_dbg_fn,
1236                                         but_store->py_dbg_ln);
1237                         }
1238                         else {
1239                                 BKE_report(op->reports, RPT_ERROR, "Active button is not from a script, cannot edit source");
1240                                 ret = OPERATOR_CANCELLED;
1241                         }
1242                 }
1243                 else {
1244                         BKE_report(op->reports, RPT_ERROR, "Active button match cannot be found");
1245                         ret = OPERATOR_CANCELLED;
1246                 }
1247
1248
1249                 ui_editsource_active_but_clear();
1250
1251                 // printf("%s: end\n", __func__);
1252
1253                 return ret;
1254         }
1255         else {
1256                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
1257                 return OPERATOR_CANCELLED;
1258         }
1259 }
1260
1261 static void UI_OT_editsource(wmOperatorType *ot)
1262 {
1263         /* identifiers */
1264         ot->name = "Edit Source";
1265         ot->idname = "UI_OT_editsource";
1266         ot->description = "Edit UI source code of the active button";
1267
1268         /* callbacks */
1269         ot->exec = editsource_exec;
1270 }
1271
1272 /* ------------------------------------------------------------------------- */
1273
1274 /**
1275  * EditTranslation utility funcs and operator,
1276  * \note: this includes utility functions and button matching checks.
1277  * this only works in conjunction with a py operator!
1278  */
1279 static void edittranslation_find_po_file(const char *root, const char *uilng, char *path, const size_t maxlen)
1280 {
1281         char tstr[32]; /* Should be more than enough! */
1282
1283         /* First, full lang code. */
1284         BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
1285         BLI_join_dirfile(path, maxlen, root, uilng);
1286         BLI_path_append(path, maxlen, tstr);
1287         if (BLI_is_file(path))
1288                 return;
1289
1290         /* Now try without the second iso code part (_ES in es_ES). */
1291         {
1292                 const char *tc = NULL;
1293                 size_t szt = 0;
1294                 tstr[0] = '\0';
1295
1296                 tc = strchr(uilng, '_');
1297                 if (tc) {
1298                         szt = tc - uilng;
1299                         if (szt < sizeof(tstr)) /* Paranoid, should always be true! */
1300                                 BLI_strncpy(tstr, uilng, szt + 1); /* +1 for '\0' char! */
1301                 }
1302                 if (tstr[0]) {
1303                         /* Because of some codes like sr_SR@latin... */
1304                         tc = strchr(uilng, '@');
1305                         if (tc)
1306                                 BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
1307
1308                         BLI_join_dirfile(path, maxlen, root, tstr);
1309                         strcat(tstr, ".po");
1310                         BLI_path_append(path, maxlen, tstr);
1311                         if (BLI_is_file(path))
1312                                 return;
1313                 }
1314         }
1315
1316         /* Else no po file! */
1317         path[0] = '\0';
1318 }
1319
1320 static int edittranslation_exec(bContext *C, wmOperator *op)
1321 {
1322         uiBut *but = UI_context_active_but_get(C);
1323         int ret = OPERATOR_CANCELLED;
1324
1325         if (but) {
1326                 wmOperatorType *ot;
1327                 PointerRNA ptr;
1328                 char popath[FILE_MAX];
1329                 const char *root = U.i18ndir;
1330                 const char *uilng = BLT_lang_get();
1331
1332                 uiStringInfo but_label = {BUT_GET_LABEL, NULL};
1333                 uiStringInfo rna_label = {BUT_GET_RNA_LABEL, NULL};
1334                 uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
1335                 uiStringInfo but_tip = {BUT_GET_TIP, NULL};
1336                 uiStringInfo rna_tip = {BUT_GET_RNA_TIP, NULL};
1337                 uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
1338                 uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
1339                 uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
1340                 uiStringInfo rna_enum = {BUT_GET_RNAENUM_IDENTIFIER, NULL};
1341                 uiStringInfo rna_ctxt = {BUT_GET_RNA_LABEL_CONTEXT, NULL};
1342
1343                 if (!BLI_is_dir(root)) {
1344                         BKE_report(
1345                                 op->reports, RPT_ERROR,
1346                                 "Please set your Preferences' 'Translation Branches "
1347                                 "Directory' path to a valid directory");
1348                         return OPERATOR_CANCELLED;
1349                 }
1350                 ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
1351                 if (ot == NULL) {
1352                         BKE_reportf(
1353                                 op->reports, RPT_ERROR,
1354                                 "Could not find operator '%s'! Please enable ui_translate add-on "
1355                                 "in the User Preferences", EDTSRC_I18N_OP_NAME);
1356                         return OPERATOR_CANCELLED;
1357                 }
1358                 /* Try to find a valid po file for current language... */
1359                 edittranslation_find_po_file(root, uilng, popath, FILE_MAX);
1360                 /* printf("po path: %s\n", popath); */
1361                 if (popath[0] == '\0') {
1362                         BKE_reportf(op->reports, RPT_ERROR, "No valid po found for language '%s' under %s", uilng, root);
1363                         return OPERATOR_CANCELLED;
1364                 }
1365
1366                 UI_but_string_info_get(
1367                         C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
1368                         &rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);
1369
1370                 WM_operator_properties_create_ptr(&ptr, ot);
1371                 RNA_string_set(&ptr, "lang", uilng);
1372                 RNA_string_set(&ptr, "po_file", popath);
1373                 RNA_string_set(&ptr, "but_label", but_label.strinfo);
1374                 RNA_string_set(&ptr, "rna_label", rna_label.strinfo);
1375                 RNA_string_set(&ptr, "enum_label", enum_label.strinfo);
1376                 RNA_string_set(&ptr, "but_tip", but_tip.strinfo);
1377                 RNA_string_set(&ptr, "rna_tip", rna_tip.strinfo);
1378                 RNA_string_set(&ptr, "enum_tip", enum_tip.strinfo);
1379                 RNA_string_set(&ptr, "rna_struct", rna_struct.strinfo);
1380                 RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
1381                 RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
1382                 RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
1383                 ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
1384
1385                 /* Clean up */
1386                 if (but_label.strinfo)
1387                         MEM_freeN(but_label.strinfo);
1388                 if (rna_label.strinfo)
1389                         MEM_freeN(rna_label.strinfo);
1390                 if (enum_label.strinfo)
1391                         MEM_freeN(enum_label.strinfo);
1392                 if (but_tip.strinfo)
1393                         MEM_freeN(but_tip.strinfo);
1394                 if (rna_tip.strinfo)
1395                         MEM_freeN(rna_tip.strinfo);
1396                 if (enum_tip.strinfo)
1397                         MEM_freeN(enum_tip.strinfo);
1398                 if (rna_struct.strinfo)
1399                         MEM_freeN(rna_struct.strinfo);
1400                 if (rna_prop.strinfo)
1401                         MEM_freeN(rna_prop.strinfo);
1402                 if (rna_enum.strinfo)
1403                         MEM_freeN(rna_enum.strinfo);
1404                 if (rna_ctxt.strinfo)
1405                         MEM_freeN(rna_ctxt.strinfo);
1406
1407                 return ret;
1408         }
1409         else {
1410                 BKE_report(op->reports, RPT_ERROR, "Active button not found");
1411                 return OPERATOR_CANCELLED;
1412         }
1413 }
1414
1415 static void UI_OT_edittranslation_init(wmOperatorType *ot)
1416 {
1417         /* identifiers */
1418         ot->name = "Edit Translation";
1419         ot->idname = "UI_OT_edittranslation_init";
1420         ot->description = "Edit i18n in current language for the active button";
1421
1422         /* callbacks */
1423         ot->exec = edittranslation_exec;
1424 }
1425
1426 #endif /* WITH_PYTHON */
1427
1428 static int reloadtranslation_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
1429 {
1430         BLT_lang_init();
1431         BLF_cache_clear();
1432         BLT_lang_set(NULL);
1433         UI_reinit_font();
1434         return OPERATOR_FINISHED;
1435 }
1436
1437 static void UI_OT_reloadtranslation(wmOperatorType *ot)
1438 {
1439         /* identifiers */
1440         ot->name = "Reload Translation";
1441         ot->idname = "UI_OT_reloadtranslation";
1442         ot->description = "Force a full reload of UI translation";
1443
1444         /* callbacks */
1445         ot->exec = reloadtranslation_exec;
1446 }
1447
1448
1449 static ARegion *region_event_inside_for_screen(bContext *C, const int xy[2])
1450 {
1451         bScreen *sc = CTX_wm_screen(C);
1452         if (sc) {
1453                 for (ARegion *ar = sc->regionbase.first; ar; ar = ar->next) {
1454                         if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) {
1455                                 return ar;
1456                         }
1457                 }
1458         }
1459         return NULL;
1460 }
1461
1462 static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1463 {
1464         const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
1465         ARegion *ar_prev = CTX_wm_region(C);
1466         ARegion *ar = region_event_inside_for_screen(C, &event->x);
1467
1468         if (ar == NULL) {
1469                 ar = ar_prev;
1470         }
1471
1472         CTX_wm_region_set(C, ar);
1473         uiBut *but = UI_context_active_but_get(C);
1474         CTX_wm_region_set(C, ar_prev);
1475
1476         if (but == NULL) {
1477                 return OPERATOR_PASS_THROUGH;
1478         }
1479         if (skip_depressed && (but->flag & (UI_SELECT | UI_SELECT_DRAW))) {
1480                 return OPERATOR_PASS_THROUGH;
1481         }
1482
1483         /* Weak, this is a workaround for 'UI_but_is_tool', which checks the operator type,
1484          * having this avoids a minor drawing glitch. */
1485         void *but_optype = but->optype;
1486
1487         UI_but_execute(C, but);
1488
1489         but->optype = but_optype;
1490
1491         WM_event_add_mousemove(C);
1492
1493         return OPERATOR_FINISHED;
1494 }
1495
1496 static void UI_OT_button_execute(wmOperatorType *ot)
1497 {
1498         ot->name = "Press Button";
1499         ot->idname = "UI_OT_button_execute";
1500         ot->description = "Presses active button";
1501
1502         ot->invoke = ui_button_press_invoke;
1503         ot->flag = OPTYPE_INTERNAL;
1504
1505         RNA_def_boolean(ot->srna, "skip_depressed", 0, "Skip Depressed", "");
1506 }
1507
1508 bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip))
1509 {
1510         /* should only return true for regions that include buttons, for now
1511          * return true always */
1512         if (drag->type == WM_DRAG_COLOR) {
1513                 SpaceImage *sima = CTX_wm_space_image(C);
1514                 ARegion *ar = CTX_wm_region(C);
1515
1516                 if (UI_but_active_drop_color(C))
1517                         return 1;
1518
1519                 if (sima && (sima->mode == SI_MODE_PAINT) &&
1520                     sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
1521                 {
1522                         return 1;
1523                 }
1524         }
1525
1526         return 0;
1527 }
1528
1529 void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
1530 {
1531         uiDragColorHandle *drag_info = drag->poin;
1532
1533         RNA_float_set_array(drop->ptr, "color", drag_info->color);
1534         RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
1535 }
1536
1537 static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1538 {
1539         ARegion *ar = CTX_wm_region(C);
1540         uiBut *but = NULL;
1541         float color[4];
1542         bool gamma;
1543
1544         RNA_float_get_array(op->ptr, "color", color);
1545         gamma = RNA_boolean_get(op->ptr, "gamma");
1546
1547         /* find button under mouse, check if it has RNA color property and
1548          * if it does copy the data */
1549         but = ui_but_find_active_in_region(ar);
1550
1551         if (but && but->type == UI_BTYPE_COLOR && but->rnaprop) {
1552                 const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
1553                 BLI_assert(color_len <= 4);
1554
1555                 /* keep alpha channel as-is */
1556                 if (color_len == 4) {
1557                         color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
1558                 }
1559
1560                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
1561                         if (!gamma)
1562                                 IMB_colormanagement_scene_linear_to_srgb_v3(color);
1563                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
1564                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
1565                 }
1566                 else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
1567                         if (gamma)
1568                                 IMB_colormanagement_srgb_to_scene_linear_v3(color);
1569                         RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
1570                         RNA_property_update(C, &but->rnapoin, but->rnaprop);
1571                 }
1572         }
1573         else {
1574                 if (gamma) {
1575                         srgb_to_linearrgb_v3_v3(color, color);
1576                 }
1577
1578                 ED_imapaint_bucket_fill(C, color, op);
1579         }
1580
1581         ED_region_tag_redraw(ar);
1582
1583         return OPERATOR_FINISHED;
1584 }
1585
1586
1587 static void UI_OT_drop_color(wmOperatorType *ot)
1588 {
1589         ot->name = "Drop Color";
1590         ot->idname = "UI_OT_drop_color";
1591         ot->description = "Drop colors to buttons";
1592
1593         ot->invoke = drop_color_invoke;
1594         ot->flag = OPTYPE_INTERNAL;
1595
1596         RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
1597         RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
1598 }
1599
1600
1601 /* ********************************************************* */
1602 /* Registration */
1603
1604 void ED_operatortypes_ui(void)
1605 {
1606         WM_operatortype_append(UI_OT_reset_default_theme);
1607         WM_operatortype_append(UI_OT_copy_data_path_button);
1608         WM_operatortype_append(UI_OT_copy_python_command_button);
1609         WM_operatortype_append(UI_OT_reset_default_button);
1610         WM_operatortype_append(UI_OT_assign_default_button);
1611         WM_operatortype_append(UI_OT_unset_property_button);
1612         WM_operatortype_append(UI_OT_override_type_set_button);
1613         WM_operatortype_append(UI_OT_override_remove_button);
1614         WM_operatortype_append(UI_OT_copy_to_selected_button);
1615         WM_operatortype_append(UI_OT_jump_to_target_button);
1616         WM_operatortype_append(UI_OT_reports_to_textblock);  /* XXX: temp? */
1617         WM_operatortype_append(UI_OT_drop_color);
1618 #ifdef WITH_PYTHON
1619         WM_operatortype_append(UI_OT_editsource);
1620         WM_operatortype_append(UI_OT_edittranslation_init);
1621 #endif
1622         WM_operatortype_append(UI_OT_reloadtranslation);
1623         WM_operatortype_append(UI_OT_button_execute);
1624
1625         /* external */
1626         WM_operatortype_append(UI_OT_eyedropper_color);
1627         WM_operatortype_append(UI_OT_eyedropper_colorband);
1628         WM_operatortype_append(UI_OT_eyedropper_colorband_point);
1629         WM_operatortype_append(UI_OT_eyedropper_id);
1630         WM_operatortype_append(UI_OT_eyedropper_depth);
1631         WM_operatortype_append(UI_OT_eyedropper_driver);
1632 }
1633
1634 /**
1635  * \brief User Interface Keymap
1636  */
1637 void ED_keymap_ui(wmKeyConfig *keyconf)
1638 {
1639         WM_keymap_ensure(keyconf, "User Interface", 0, 0);
1640
1641         eyedropper_modal_keymap(keyconf);
1642         eyedropper_colorband_modal_keymap(keyconf);
1643 }