synched with trunk at revision 32129
[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 #include <stdio.h>
29 #include <math.h>
30 #include <string.h>
31
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_scene_types.h"
36 #include "DNA_screen_types.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math_color.h"
40
41 #include "BKE_context.h"
42
43 #include "RNA_access.h"
44 #include "RNA_define.h"
45
46 #include "BIF_gl.h"
47
48 #include "UI_interface.h"
49
50 #include "interface_intern.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55
56
57 /* ********************************************************** */
58
59 typedef struct Eyedropper {
60         PointerRNA ptr;
61         PropertyRNA *prop;
62         int index;
63 } Eyedropper;
64
65 static int eyedropper_init(bContext *C, wmOperator *op)
66 {
67         Eyedropper *eye;
68         
69         op->customdata= eye= MEM_callocN(sizeof(Eyedropper), "Eyedropper");
70         
71         uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index);
72         
73         return (eye->ptr.data && eye->prop && RNA_property_editable(&eye->ptr, eye->prop));
74 }
75  
76 static void eyedropper_exit(bContext *C, wmOperator *op)
77 {
78         WM_cursor_restore(CTX_wm_window(C));
79         
80         if(op->customdata)
81                 MEM_freeN(op->customdata);
82         op->customdata= NULL;
83 }
84
85 static int eyedropper_cancel(bContext *C, wmOperator *op)
86 {
87         eyedropper_exit(C, op);
88         return OPERATOR_CANCELLED;
89 }
90
91 static void eyedropper_sample(bContext *C, Eyedropper *eye, short mx, short my)
92 {
93         if(RNA_property_type(eye->prop) == PROP_FLOAT) {
94                 const int color_manage = CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT;
95                 float col[4];
96         
97                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
98                 
99                 glReadBuffer(GL_FRONT);
100                 glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, col);
101                 glReadBuffer(GL_BACK);
102         
103                 if (RNA_property_array_length(&eye->ptr, eye->prop) < 3) return;
104
105                 /* convert from screen (srgb) space to linear rgb space */
106                 if (color_manage && RNA_property_subtype(eye->prop) == PROP_COLOR)
107                         srgb_to_linearrgb_v3_v3(col, col);
108                 
109                 RNA_property_float_set_array(&eye->ptr, eye->prop, col);
110                 
111                 RNA_property_update(C, &eye->ptr, eye->prop);
112         }
113 }
114
115 /* main modal status check */
116 static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
117 {
118         Eyedropper *eye = (Eyedropper *)op->customdata;
119         
120         switch(event->type) {
121                 case ESCKEY:
122                 case RIGHTMOUSE:
123                         return eyedropper_cancel(C, op);
124                 case LEFTMOUSE:
125                         if(event->val==KM_RELEASE) {
126                                 eyedropper_sample(C, eye, event->x, event->y);
127                                 eyedropper_exit(C, op);
128                                 return OPERATOR_FINISHED;
129                         }
130                         break;
131         }
132         
133         return OPERATOR_RUNNING_MODAL;
134 }
135
136 /* Modal Operator init */
137 static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *event)
138 {
139         /* init */
140         if (eyedropper_init(C, op)) {
141                 WM_cursor_modal(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
142
143                 /* add temp handler */
144                 WM_event_add_modal_handler(C, op);
145                 
146                 return OPERATOR_RUNNING_MODAL;
147         } else {
148                 eyedropper_exit(C, op);
149                 return OPERATOR_CANCELLED;
150         }
151 }
152
153 /* Repeat operator */
154 static int eyedropper_exec (bContext *C, wmOperator *op)
155 {
156         /* init */
157         if (eyedropper_init(C, op)) {
158                 
159                 /* do something */
160                 
161                 /* cleanup */
162                 eyedropper_exit(C, op);
163                 
164                 return OPERATOR_FINISHED;
165         } else {
166                 return OPERATOR_CANCELLED;
167         }
168 }
169
170 static int eyedropper_poll(bContext *C)
171 {
172         if (!CTX_wm_window(C)) return 0;
173         else return 1;
174 }
175
176 void UI_OT_eyedropper(wmOperatorType *ot)
177 {
178         /* identifiers */
179         ot->name= "Eyedropper";
180         ot->idname= "UI_OT_eyedropper";
181         ot->description= "Sample a color from the Blender Window to store in a property";
182         
183         /* api callbacks */
184         ot->invoke= eyedropper_invoke;
185         ot->modal= eyedropper_modal;
186         ot->cancel= eyedropper_cancel;
187         ot->exec= eyedropper_exec;
188         ot->poll= eyedropper_poll;
189         
190         /* flags */
191         ot->flag= OPTYPE_BLOCKING;
192         
193         /* properties */
194 }
195
196 /* Reset Default Theme ------------------------ */
197
198 static int reset_default_theme_exec(bContext *C, wmOperator *op)
199 {
200         ui_theme_init_default();
201         WM_event_add_notifier(C, NC_WINDOW, NULL);
202         
203         return OPERATOR_FINISHED;
204 }
205
206 void UI_OT_reset_default_theme(wmOperatorType *ot)
207 {
208         /* identifiers */
209         ot->name= "Reset to Default Theme";
210         ot->idname= "UI_OT_reset_default_theme";
211         ot->description= "Reset to the default theme colors";
212         
213         /* callbacks */
214         ot->exec= reset_default_theme_exec;
215         
216         /* flags */
217         ot->flag= OPTYPE_REGISTER;
218 }
219
220 /* Copy Data Path Operator ------------------------ */
221
222 static int copy_data_path_button_exec(bContext *C, wmOperator *op)
223 {
224         PointerRNA ptr;
225         PropertyRNA *prop;
226         char *path;
227         int success= 0;
228         int index;
229
230         /* try to create driver using property retrieved from UI */
231         uiContextActiveProperty(C, &ptr, &prop, &index);
232
233         if (ptr.id.data && ptr.data && prop) {
234                 path= RNA_path_from_ID_to_property(&ptr, prop);
235                 
236                 if (path) {
237                         WM_clipboard_text_set(path, FALSE);
238                         MEM_freeN(path);
239                 }
240         }
241
242         /* since we're just copying, we don't really need to do anything else...*/
243         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
244 }
245
246 void UI_OT_copy_data_path_button(wmOperatorType *ot)
247 {
248         /* identifiers */
249         ot->name= "Copy Data Path";
250         ot->idname= "UI_OT_copy_data_path_button";
251         ot->description= "Copy the RNA data path for this property to the clipboard";
252
253         /* callbacks */
254         ot->exec= copy_data_path_button_exec;
255         //op->poll= ??? // TODO: need to have some valid property before this can be done
256
257         /* flags */
258         ot->flag= OPTYPE_REGISTER;
259 }
260
261 /* Reset to Default Values Button Operator ------------------------ */
262
263 static int reset_default_button_poll(bContext *C)
264 {
265         PointerRNA ptr;
266         PropertyRNA *prop;
267         int index;
268
269         uiContextActiveProperty(C, &ptr, &prop, &index);
270         
271         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
272 }
273
274 static int reset_default_button_exec(bContext *C, wmOperator *op)
275 {
276         PointerRNA ptr;
277         PropertyRNA *prop;
278         int success= 0;
279         int index, all = RNA_boolean_get(op->ptr, "all");
280
281         /* try to reset the nominated setting to its default value */
282         uiContextActiveProperty(C, &ptr, &prop, &index);
283         
284         /* if there is a valid property that is editable... */
285         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
286                 if(RNA_property_reset(&ptr, prop, (all)? -1: index)) {
287                         /* perform updates required for this property */
288                         RNA_property_update(C, &ptr, prop);
289                         success= 1;
290                 }
291         }
292         
293         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
294 }
295
296 void UI_OT_reset_default_button(wmOperatorType *ot)
297 {
298         /* identifiers */
299         ot->name= "Reset to Default Value";
300         ot->idname= "UI_OT_reset_default_button";
301         ot->description= "Reset this property's value to its default value";
302
303         /* callbacks */
304         ot->poll= reset_default_button_poll;
305         ot->exec= reset_default_button_exec;
306
307         /* flags */
308         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
309         
310         /* properties */
311         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
312 }
313
314 /* Copy To Selected Operator ------------------------ */
315
316 static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb)
317 {
318         if(RNA_struct_is_a(ptr->type, &RNA_Object))
319                 *lb = CTX_data_collection_get(C, "selected_editable_objects");
320         else if(RNA_struct_is_a(ptr->type, &RNA_EditBone))
321                 *lb = CTX_data_collection_get(C, "selected_editable_bones");
322         else if(RNA_struct_is_a(ptr->type, &RNA_PoseBone))
323                 *lb = CTX_data_collection_get(C, "selected_pose_bones");
324         else if(RNA_struct_is_a(ptr->type, &RNA_Sequence))
325                 *lb = CTX_data_collection_get(C, "selected_editable_sequences");
326         else
327                 return 0;
328         
329         return 1;
330 }
331
332 static int copy_to_selected_button_poll(bContext *C)
333 {
334         PointerRNA ptr;
335         PropertyRNA *prop;
336         int index, success= 0;
337
338         uiContextActiveProperty(C, &ptr, &prop, &index);
339
340         if (ptr.data && prop) {
341                 CollectionPointerLink *link;
342                 ListBase lb;
343
344                 if(copy_to_selected_list(C, &ptr, &lb)) {
345                         for(link= lb.first; link; link=link->next)
346                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop))
347                                         success= 1;
348
349                         BLI_freelistN(&lb);
350                 }
351         }
352
353         return success;
354 }
355
356 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
357 {
358         PointerRNA ptr;
359         PropertyRNA *prop;
360         int success= 0;
361         int index, all = RNA_boolean_get(op->ptr, "all");
362
363         /* try to reset the nominated setting to its default value */
364         uiContextActiveProperty(C, &ptr, &prop, &index);
365         
366         /* if there is a valid property that is editable... */
367         if (ptr.data && prop) {
368                 CollectionPointerLink *link;
369                 ListBase lb;
370
371                 if(copy_to_selected_list(C, &ptr, &lb)) {
372                         for(link= lb.first; link; link=link->next) {
373                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop)) {
374                                         if(RNA_property_copy(&link->ptr, &ptr, prop, (all)? -1: index)) {
375                                                 RNA_property_update(C, &link->ptr, prop);
376                                                 success= 1;
377                                         }
378                                 }
379                         }
380
381                         BLI_freelistN(&lb);
382                 }
383         }
384         
385         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
386 }
387
388 void UI_OT_copy_to_selected_button(wmOperatorType *ot)
389 {
390         /* identifiers */
391         ot->name= "Copy To Selected";
392         ot->idname= "UI_OT_copy_to_selected_button";
393         ot->description= "Copy property from this object to selected objects or bones";
394
395         /* callbacks */
396         ot->poll= copy_to_selected_button_poll;
397         ot->exec= copy_to_selected_button_exec;
398
399         /* flags */
400         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
401
402         /* properties */
403         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
404 }
405  
406 /* ********************************************************* */
407 /* Registration */
408
409 void UI_buttons_operatortypes(void)
410 {
411         WM_operatortype_append(UI_OT_eyedropper);
412         WM_operatortype_append(UI_OT_reset_default_theme);
413         WM_operatortype_append(UI_OT_copy_data_path_button);
414         WM_operatortype_append(UI_OT_reset_default_button);
415         WM_operatortype_append(UI_OT_copy_to_selected_button);
416 }
417