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