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