svn merge -r39834:40222 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / editors / interface / interface_ops.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  * 
23  * Contributor(s): Blender Foundation, Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/interface/interface_ops.c
29  *  \ingroup edinterface
30  */
31
32
33 #include <stdio.h>
34 #include <math.h>
35 #include <string.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
42
43 #include "BLI_blenlib.h"
44 #include "BLI_math_color.h"
45 #include "BLI_utildefines.h"
46
47 #include "BLF_api.h"
48
49 #include "BKE_context.h"
50 #include "BKE_global.h"
51 #include "BKE_text.h" /* for UI_OT_reports_to_text */
52 #include "BKE_report.h"
53
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56
57 #include "BIF_gl.h"
58
59 #include "UI_interface.h"
60
61 #include "interface_intern.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66
67
68 /* ********************************************************** */
69
70 typedef struct Eyedropper {
71         PointerRNA ptr;
72         PropertyRNA *prop;
73         int index;
74 } Eyedropper;
75
76 static int eyedropper_init(bContext *C, wmOperator *op)
77 {
78         Eyedropper *eye;
79         
80         op->customdata= eye= MEM_callocN(sizeof(Eyedropper), "Eyedropper");
81         
82         uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index);
83         
84         return (eye->ptr.data && eye->prop && RNA_property_editable(&eye->ptr, eye->prop));
85 }
86  
87 static void eyedropper_exit(bContext *C, wmOperator *op)
88 {
89         WM_cursor_restore(CTX_wm_window(C));
90         
91         if(op->customdata)
92                 MEM_freeN(op->customdata);
93         op->customdata= NULL;
94 }
95
96 static int eyedropper_cancel(bContext *C, wmOperator *op)
97 {
98         eyedropper_exit(C, op);
99         return OPERATOR_CANCELLED;
100 }
101
102 static void eyedropper_sample(bContext *C, Eyedropper *eye, int mx, int my)
103 {
104         if(RNA_property_type(eye->prop) == PROP_FLOAT) {
105                 const int color_manage = CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT;
106                 float col[4];
107         
108                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
109                 
110                 glReadBuffer(GL_FRONT);
111                 glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, col);
112                 glReadBuffer(GL_BACK);
113         
114                 if (RNA_property_array_length(&eye->ptr, eye->prop) < 3) return;
115
116                 /* convert from screen (srgb) space to linear rgb space */
117                 if (color_manage && RNA_property_subtype(eye->prop) == PROP_COLOR)
118                         srgb_to_linearrgb_v3_v3(col, col);
119                 
120                 RNA_property_float_set_array(&eye->ptr, eye->prop, col);
121                 
122                 RNA_property_update(C, &eye->ptr, eye->prop);
123         }
124 }
125
126 /* main modal status check */
127 static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
128 {
129         Eyedropper *eye = (Eyedropper *)op->customdata;
130         
131         switch(event->type) {
132                 case ESCKEY:
133                 case RIGHTMOUSE:
134                         return eyedropper_cancel(C, op);
135                 case LEFTMOUSE:
136                         if(event->val==KM_RELEASE) {
137                                 eyedropper_sample(C, eye, event->x, event->y);
138                                 eyedropper_exit(C, op);
139                                 return OPERATOR_FINISHED;
140                         }
141                         break;
142         }
143         
144         return OPERATOR_RUNNING_MODAL;
145 }
146
147 /* Modal Operator init */
148 static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
149 {
150         /* init */
151         if (eyedropper_init(C, op)) {
152                 WM_cursor_modal(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
153
154                 /* add temp handler */
155                 WM_event_add_modal_handler(C, op);
156                 
157                 return OPERATOR_RUNNING_MODAL;
158         } else {
159                 eyedropper_exit(C, op);
160                 return OPERATOR_CANCELLED;
161         }
162 }
163
164 /* Repeat operator */
165 static int eyedropper_exec (bContext *C, wmOperator *op)
166 {
167         /* init */
168         if (eyedropper_init(C, op)) {
169                 
170                 /* do something */
171                 
172                 /* cleanup */
173                 eyedropper_exit(C, op);
174                 
175                 return OPERATOR_FINISHED;
176         } else {
177                 return OPERATOR_CANCELLED;
178         }
179 }
180
181 static int eyedropper_poll(bContext *C)
182 {
183         if (!CTX_wm_window(C)) return 0;
184         else return 1;
185 }
186
187 static void UI_OT_eyedropper(wmOperatorType *ot)
188 {
189         /* identifiers */
190         ot->name= "Eyedropper";
191         ot->idname= "UI_OT_eyedropper";
192         ot->description= "Sample a color from the Blender Window to store in a property";
193         
194         /* api callbacks */
195         ot->invoke= eyedropper_invoke;
196         ot->modal= eyedropper_modal;
197         ot->cancel= eyedropper_cancel;
198         ot->exec= eyedropper_exec;
199         ot->poll= eyedropper_poll;
200         
201         /* flags */
202         ot->flag= OPTYPE_BLOCKING;
203         
204         /* properties */
205 }
206
207 /* Reset Default Theme ------------------------ */
208
209 static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
210 {
211         ui_theme_init_default();
212         WM_event_add_notifier(C, NC_WINDOW, NULL);
213         
214         return OPERATOR_FINISHED;
215 }
216
217 static void UI_OT_reset_default_theme(wmOperatorType *ot)
218 {
219         /* identifiers */
220         ot->name= _("Reset to Default Theme");
221         ot->idname= "UI_OT_reset_default_theme";
222         ot->description= _("Reset to the default theme colors");
223         
224         /* callbacks */
225         ot->exec= reset_default_theme_exec;
226         
227         /* flags */
228         ot->flag= OPTYPE_REGISTER;
229 }
230
231 /* Copy Data Path Operator ------------------------ */
232
233 static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
234 {
235         PointerRNA ptr;
236         PropertyRNA *prop;
237         char *path;
238         int success= 0;
239         int index;
240
241         /* try to create driver using property retrieved from UI */
242         uiContextActiveProperty(C, &ptr, &prop, &index);
243
244         if (ptr.id.data && ptr.data && prop) {
245                 path= RNA_path_from_ID_to_property(&ptr, prop);
246                 
247                 if (path) {
248                         WM_clipboard_text_set(path, FALSE);
249                         MEM_freeN(path);
250                 }
251         }
252
253         /* since we're just copying, we don't really need to do anything else...*/
254         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
255 }
256
257 static void UI_OT_copy_data_path_button(wmOperatorType *ot)
258 {
259         /* identifiers */
260         ot->name= "Copy Data Path";
261         ot->idname= "UI_OT_copy_data_path_button";
262         ot->description= "Copy the RNA data path for this property to the clipboard";
263
264         /* callbacks */
265         ot->exec= copy_data_path_button_exec;
266         //op->poll= ??? // TODO: need to have some valid property before this can be done
267
268         /* flags */
269         ot->flag= OPTYPE_REGISTER;
270 }
271
272 /* Reset to Default Values Button Operator ------------------------ */
273
274 static int reset_default_button_poll(bContext *C)
275 {
276         PointerRNA ptr;
277         PropertyRNA *prop;
278         int index;
279
280         uiContextActiveProperty(C, &ptr, &prop, &index);
281         
282         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
283 }
284
285 static int reset_default_button_exec(bContext *C, wmOperator *op)
286 {
287         PointerRNA ptr;
288         PropertyRNA *prop;
289         int success= 0;
290         int index, all = RNA_boolean_get(op->ptr, "all");
291
292         /* try to reset the nominated setting to its default value */
293         uiContextActiveProperty(C, &ptr, &prop, &index);
294         
295         /* if there is a valid property that is editable... */
296         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
297                 if(RNA_property_reset(&ptr, prop, (all)? -1: index)) {
298                         /* perform updates required for this property */
299                         RNA_property_update(C, &ptr, prop);
300                         success= 1;
301                 }
302         }
303         
304         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
305 }
306
307 static void UI_OT_reset_default_button(wmOperatorType *ot)
308 {
309         /* identifiers */
310         ot->name= _("Reset to Default Value");
311         ot->idname= "UI_OT_reset_default_button";
312         ot->description= _("Reset this property's value to its default value");
313
314         /* callbacks */
315         ot->poll= reset_default_button_poll;
316         ot->exec= reset_default_button_exec;
317
318         /* flags */
319         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
320         
321         /* properties */
322         RNA_def_boolean(ot->srna, "all", 1, _("All"), _("Reset to default values all elements of the array."));
323 }
324
325 /* Copy To Selected Operator ------------------------ */
326
327 static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb)
328 {
329         if(RNA_struct_is_a(ptr->type, &RNA_Object))
330                 *lb = CTX_data_collection_get(C, "selected_editable_objects");
331         else if(RNA_struct_is_a(ptr->type, &RNA_EditBone))
332                 *lb = CTX_data_collection_get(C, "selected_editable_bones");
333         else if(RNA_struct_is_a(ptr->type, &RNA_PoseBone))
334                 *lb = CTX_data_collection_get(C, "selected_pose_bones");
335         else if(RNA_struct_is_a(ptr->type, &RNA_Sequence))
336                 *lb = CTX_data_collection_get(C, "selected_editable_sequences");
337         else
338                 return 0;
339         
340         return 1;
341 }
342
343 static int copy_to_selected_button_poll(bContext *C)
344 {
345         PointerRNA ptr;
346         PropertyRNA *prop;
347         int index, success= 0;
348
349         uiContextActiveProperty(C, &ptr, &prop, &index);
350
351         if (ptr.data && prop) {
352                 CollectionPointerLink *link;
353                 ListBase lb;
354
355                 if(copy_to_selected_list(C, &ptr, &lb)) {
356                         for(link= lb.first; link; link=link->next)
357                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop))
358                                         success= 1;
359
360                         BLI_freelistN(&lb);
361                 }
362         }
363
364         return success;
365 }
366
367 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
368 {
369         PointerRNA ptr;
370         PropertyRNA *prop;
371         int success= 0;
372         int index, all = RNA_boolean_get(op->ptr, "all");
373
374         /* try to reset the nominated setting to its default value */
375         uiContextActiveProperty(C, &ptr, &prop, &index);
376         
377         /* if there is a valid property that is editable... */
378         if (ptr.data && prop) {
379                 CollectionPointerLink *link;
380                 ListBase lb;
381
382                 if(copy_to_selected_list(C, &ptr, &lb)) {
383                         for(link= lb.first; link; link=link->next) {
384                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop)) {
385                                         if(RNA_property_copy(&link->ptr, &ptr, prop, (all)? -1: index)) {
386                                                 RNA_property_update(C, &link->ptr, prop);
387                                                 success= 1;
388                                         }
389                                 }
390                         }
391
392                         BLI_freelistN(&lb);
393                 }
394         }
395         
396         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
397 }
398
399 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
400 {
401         /* identifiers */
402         ot->name= _("Copy To Selected");
403         ot->idname= "UI_OT_copy_to_selected_button";
404         ot->description= _("Copy property from this object to selected objects or bones");
405
406         /* callbacks */
407         ot->poll= copy_to_selected_button_poll;
408         ot->exec= copy_to_selected_button_exec;
409
410         /* flags */
411         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
412
413         /* properties */
414         RNA_def_boolean(ot->srna, "all", 1, _("All"), _("Reset to default values all elements of the array."));
415 }
416
417 /* Reports to Textblock Operator ------------------------ */
418
419 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere 
420  * when there are too many to display...
421  */
422
423 static int reports_to_text_poll(bContext *C)
424 {
425         return CTX_wm_reports(C) != NULL;
426 }
427
428 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
429 {
430         ReportList *reports = CTX_wm_reports(C);
431         Text *txt;
432         char *str;
433         
434         /* create new text-block to write to */
435         txt = add_empty_text("Recent Reports");
436         
437         /* convert entire list to a display string, and add this to the text-block
438          *      - if commandline debug option enabled, show debug reports too
439          *      - otherwise, up to info (which is what users normally see)
440          */
441         str = BKE_reports_string(reports, (G.f & G_DEBUG)? RPT_DEBUG : RPT_INFO);
442         
443         write_text(txt, str);
444         MEM_freeN(str);
445         
446         return OPERATOR_FINISHED;
447 }
448
449 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
450 {
451         /* identifiers */
452         ot->name= "Reports to Text Block";
453         ot->idname= "UI_OT_reports_to_textblock";
454         ot->description= "Write the reports ";
455         
456         /* callbacks */
457         ot->poll= reports_to_text_poll;
458         ot->exec= reports_to_text_exec;
459 }
460
461 /* ********************************************************* */
462 /* Registration */
463
464 void UI_buttons_operatortypes(void)
465 {
466         WM_operatortype_append(UI_OT_eyedropper);
467         WM_operatortype_append(UI_OT_reset_default_theme);
468         WM_operatortype_append(UI_OT_copy_data_path_button);
469         WM_operatortype_append(UI_OT_reset_default_button);
470         WM_operatortype_append(UI_OT_copy_to_selected_button);
471         WM_operatortype_append(UI_OT_reports_to_textblock); // XXX: temp?
472 }
473