Fix [#21520] Using sample tool from color ramp sets alpha to 0
[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 #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(bContext *C, Eyedropper *eye, short mx, short my)
96 {
97         if(RNA_property_type(eye->prop) == PROP_FLOAT) {
98                 const int color_manage = CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT;
99                 float col[4];
100         
101                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
102                 
103                 glReadBuffer(GL_FRONT);
104                 glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, col);
105                 glReadBuffer(GL_BACK);
106         
107                 if (RNA_property_array_length(&eye->ptr, eye->prop) < 3) return;
108
109                 /* convert from screen (srgb) space to linear rgb space */
110                 if (color_manage && RNA_property_subtype(eye->prop) == PROP_COLOR)
111                         srgb_to_linearrgb_v3_v3(col, col);
112                 
113                 RNA_property_float_set_array(&eye->ptr, eye->prop, col);
114                 
115                 RNA_property_update(C, &eye->ptr, eye->prop);
116         }
117 }
118
119 /* main modal status check */
120 static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
121 {
122         Eyedropper *eye = (Eyedropper *)op->customdata;
123         
124         switch(event->type) {
125                 case ESCKEY:
126                 case RIGHTMOUSE:
127                         return eyedropper_cancel(C, op);
128                 case LEFTMOUSE:
129                         if(event->val==KM_RELEASE) {
130                                 eyedropper_sample(C, eye, event->x, event->y);
131                                 eyedropper_exit(C, op);
132                                 return OPERATOR_FINISHED;
133                         }
134                         break;
135         }
136         
137         return OPERATOR_RUNNING_MODAL;
138 }
139
140 /* Modal Operator init */
141 static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *event)
142 {
143         /* init */
144         if (eyedropper_init(C, op)) {
145                 WM_cursor_modal(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
146
147                 /* add temp handler */
148                 WM_event_add_modal_handler(C, op);
149                 
150                 return OPERATOR_RUNNING_MODAL;
151         } else {
152                 eyedropper_exit(C, op);
153                 return OPERATOR_CANCELLED;
154         }
155 }
156
157 /* Repeat operator */
158 static int eyedropper_exec (bContext *C, wmOperator *op)
159 {
160         /* init */
161         if (eyedropper_init(C, op)) {
162                 
163                 /* do something */
164                 
165                 /* cleanup */
166                 eyedropper_exit(C, op);
167                 
168                 return OPERATOR_FINISHED;
169         } else {
170                 return OPERATOR_CANCELLED;
171         }
172 }
173
174 static int eyedropper_poll(bContext *C)
175 {
176         if (!CTX_wm_window(C)) return 0;
177         else return 1;
178 }
179
180 void UI_OT_eyedropper(wmOperatorType *ot)
181 {
182         /* identifiers */
183         ot->name= "Eyedropper";
184         ot->idname= "UI_OT_eyedropper";
185         ot->description= "Sample a color from the Blender Window to store in a property";
186         
187         /* api callbacks */
188         ot->invoke= eyedropper_invoke;
189         ot->modal= eyedropper_modal;
190         ot->cancel= eyedropper_cancel;
191         ot->exec= eyedropper_exec;
192         ot->poll= eyedropper_poll;
193         
194         /* flags */
195         ot->flag= OPTYPE_BLOCKING;
196         
197         /* properties */
198 }
199
200
201 /* Copy Data Path Operator ------------------------ */
202
203 static int copy_data_path_button_exec(bContext *C, wmOperator *op)
204 {
205         PointerRNA ptr;
206         PropertyRNA *prop;
207         char *path;
208         int success= 0;
209         int index;
210
211         /* try to create driver using property retrieved from UI */
212         uiAnimContextProperty(C, &ptr, &prop, &index);
213
214         if (ptr.data && prop) {
215                 path= RNA_path_from_ID_to_property(&ptr, prop);
216                 
217                 if (path) {
218                         WM_clipboard_text_set(path, FALSE);
219                         MEM_freeN(path);
220                 }
221         }
222
223         /* since we're just copying, we don't really need to do anything else...*/
224         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
225 }
226
227 void UI_OT_copy_data_path_button(wmOperatorType *ot)
228 {
229         /* identifiers */
230         ot->name= "Copy Data Path";
231         ot->idname= "UI_OT_copy_data_path_button";
232         ot->description= "Copy the RNA data path for this property to the clipboard";
233
234         /* callbacks */
235         ot->exec= copy_data_path_button_exec;
236         //op->poll= ??? // TODO: need to have some valid property before this can be done
237
238         /* flags */
239         ot->flag= OPTYPE_REGISTER;
240 }
241
242 /* Reset to Default Values Button Operator ------------------------ */
243
244 static int reset_default_button_poll(bContext *C)
245 {
246         PointerRNA ptr;
247         PropertyRNA *prop;
248         int index;
249
250         uiAnimContextProperty(C, &ptr, &prop, &index);
251         
252         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
253 }
254
255 static int reset_default_button_exec(bContext *C, wmOperator *op)
256 {
257         PointerRNA ptr;
258         PropertyRNA *prop;
259         int success= 0;
260         int index, all = RNA_boolean_get(op->ptr, "all");
261
262         /* try to reset the nominated setting to its default value */
263         uiAnimContextProperty(C, &ptr, &prop, &index);
264         
265         /* if there is a valid property that is editable... */
266         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
267                 if(RNA_property_reset(&ptr, prop, (all)? -1: index)) {
268                         /* perform updates required for this property */
269                         RNA_property_update(C, &ptr, prop);
270                         success= 1;
271                 }
272         }
273         
274         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
275 }
276
277 void UI_OT_reset_default_button(wmOperatorType *ot)
278 {
279         /* identifiers */
280         ot->name= "Reset to Default Value";
281         ot->idname= "UI_OT_reset_default_button";
282         ot->description= "Reset this property's value to its default value";
283
284         /* callbacks */
285         ot->poll= reset_default_button_poll;
286         ot->exec= reset_default_button_exec;
287
288         /* flags */
289         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
290         
291         /* properties */
292         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
293 }
294
295 /* Copy To Selected Operator ------------------------ */
296
297 static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb)
298 {
299         if(RNA_struct_is_a(ptr->type, &RNA_Object))
300                 *lb = CTX_data_collection_get(C, "selected_editable_objects");
301         else if(RNA_struct_is_a(ptr->type, &RNA_EditBone))
302                 *lb = CTX_data_collection_get(C, "selected_editable_bones");
303         else if(RNA_struct_is_a(ptr->type, &RNA_PoseBone))
304                 *lb = CTX_data_collection_get(C, "selected_pose_bones");
305         else
306                 return 0;
307         
308         return 1;
309 }
310
311 static int copy_to_selected_button_poll(bContext *C)
312 {
313         PointerRNA ptr;
314         PropertyRNA *prop;
315         int index, success= 0;
316
317         uiAnimContextProperty(C, &ptr, &prop, &index);
318
319         if (ptr.data && prop) {
320                 CollectionPointerLink *link;
321                 ListBase lb;
322
323                 if(copy_to_selected_list(C, &ptr, &lb)) {
324                         for(link= lb.first; link; link=link->next)
325                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop))
326                                         success= 1;
327
328                         BLI_freelistN(&lb);
329                 }
330         }
331
332         return success;
333 }
334
335 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
336 {
337         PointerRNA ptr;
338         PropertyRNA *prop;
339         int success= 0;
340         int index, all = RNA_boolean_get(op->ptr, "all");
341
342         /* try to reset the nominated setting to its default value */
343         uiAnimContextProperty(C, &ptr, &prop, &index);
344         
345         /* if there is a valid property that is editable... */
346         if (ptr.data && prop) {
347                 CollectionPointerLink *link;
348                 ListBase lb;
349
350                 if(copy_to_selected_list(C, &ptr, &lb)) {
351                         for(link= lb.first; link; link=link->next) {
352                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop)) {
353                                         if(RNA_property_copy(&link->ptr, &ptr, prop, (all)? -1: index)) {
354                                                 RNA_property_update(C, &link->ptr, prop);
355                                                 success= 1;
356                                         }
357                                 }
358                         }
359
360                         BLI_freelistN(&lb);
361                 }
362         }
363         
364         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
365 }
366
367 void UI_OT_copy_to_selected_button(wmOperatorType *ot)
368 {
369         /* identifiers */
370         ot->name= "Copy To Selected";
371         ot->idname= "UI_OT_copy_to_selected_button";
372         ot->description= "Copy property from this object to selected objects or bones";
373
374         /* callbacks */
375         ot->poll= copy_to_selected_button_poll;
376         ot->exec= copy_to_selected_button_exec;
377
378         /* flags */
379         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
380
381         /* properties */
382         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
383 }
384  
385 /* ********************************************************* */
386 /* Registration */
387
388 void UI_buttons_operatortypes(void)
389 {
390         WM_operatortype_append(UI_OT_eyedropper);
391         WM_operatortype_append(UI_OT_copy_data_path_button);
392         WM_operatortype_append(UI_OT_reset_default_button);
393         WM_operatortype_append(UI_OT_copy_to_selected_button);
394 }
395