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