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