many functions in blender are not marked static but should be.
[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 #include "MEM_guardedalloc.h"
33
34 #include "DNA_scene_types.h"
35 #include "DNA_screen_types.h"
36 #include "DNA_text_types.h" /* for UI_OT_reports_to_text */
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math_color.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_text.h" /* for UI_OT_reports_to_text */
45 #include "BKE_report.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49
50 #include "BIF_gl.h"
51
52 #include "UI_interface.h"
53
54 #include "interface_intern.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59
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         uiContextActiveProperty(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 *UNUSED(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 static 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 /* Reset Default Theme ------------------------ */
201
202 static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
203 {
204         ui_theme_init_default();
205         WM_event_add_notifier(C, NC_WINDOW, NULL);
206         
207         return OPERATOR_FINISHED;
208 }
209
210 static void UI_OT_reset_default_theme(wmOperatorType *ot)
211 {
212         /* identifiers */
213         ot->name= "Reset to Default Theme";
214         ot->idname= "UI_OT_reset_default_theme";
215         ot->description= "Reset to the default theme colors";
216         
217         /* callbacks */
218         ot->exec= reset_default_theme_exec;
219         
220         /* flags */
221         ot->flag= OPTYPE_REGISTER;
222 }
223
224 /* Copy Data Path Operator ------------------------ */
225
226 static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
227 {
228         PointerRNA ptr;
229         PropertyRNA *prop;
230         char *path;
231         int success= 0;
232         int index;
233
234         /* try to create driver using property retrieved from UI */
235         uiContextActiveProperty(C, &ptr, &prop, &index);
236
237         if (ptr.id.data && ptr.data && prop) {
238                 path= RNA_path_from_ID_to_property(&ptr, prop);
239                 
240                 if (path) {
241                         WM_clipboard_text_set(path, FALSE);
242                         MEM_freeN(path);
243                 }
244         }
245
246         /* since we're just copying, we don't really need to do anything else...*/
247         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
248 }
249
250 static void UI_OT_copy_data_path_button(wmOperatorType *ot)
251 {
252         /* identifiers */
253         ot->name= "Copy Data Path";
254         ot->idname= "UI_OT_copy_data_path_button";
255         ot->description= "Copy the RNA data path for this property to the clipboard";
256
257         /* callbacks */
258         ot->exec= copy_data_path_button_exec;
259         //op->poll= ??? // TODO: need to have some valid property before this can be done
260
261         /* flags */
262         ot->flag= OPTYPE_REGISTER;
263 }
264
265 /* Reset to Default Values Button Operator ------------------------ */
266
267 static int reset_default_button_poll(bContext *C)
268 {
269         PointerRNA ptr;
270         PropertyRNA *prop;
271         int index;
272
273         uiContextActiveProperty(C, &ptr, &prop, &index);
274         
275         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
276 }
277
278 static int reset_default_button_exec(bContext *C, wmOperator *op)
279 {
280         PointerRNA ptr;
281         PropertyRNA *prop;
282         int success= 0;
283         int index, all = RNA_boolean_get(op->ptr, "all");
284
285         /* try to reset the nominated setting to its default value */
286         uiContextActiveProperty(C, &ptr, &prop, &index);
287         
288         /* if there is a valid property that is editable... */
289         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
290                 if(RNA_property_reset(&ptr, prop, (all)? -1: index)) {
291                         /* perform updates required for this property */
292                         RNA_property_update(C, &ptr, prop);
293                         success= 1;
294                 }
295         }
296         
297         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
298 }
299
300 static void UI_OT_reset_default_button(wmOperatorType *ot)
301 {
302         /* identifiers */
303         ot->name= "Reset to Default Value";
304         ot->idname= "UI_OT_reset_default_button";
305         ot->description= "Reset this property's value to its default value";
306
307         /* callbacks */
308         ot->poll= reset_default_button_poll;
309         ot->exec= reset_default_button_exec;
310
311         /* flags */
312         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
313         
314         /* properties */
315         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
316 }
317
318 /* Copy To Selected Operator ------------------------ */
319
320 static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb)
321 {
322         if(RNA_struct_is_a(ptr->type, &RNA_Object))
323                 *lb = CTX_data_collection_get(C, "selected_editable_objects");
324         else if(RNA_struct_is_a(ptr->type, &RNA_EditBone))
325                 *lb = CTX_data_collection_get(C, "selected_editable_bones");
326         else if(RNA_struct_is_a(ptr->type, &RNA_PoseBone))
327                 *lb = CTX_data_collection_get(C, "selected_pose_bones");
328         else if(RNA_struct_is_a(ptr->type, &RNA_Sequence))
329                 *lb = CTX_data_collection_get(C, "selected_editable_sequences");
330         else
331                 return 0;
332         
333         return 1;
334 }
335
336 static int copy_to_selected_button_poll(bContext *C)
337 {
338         PointerRNA ptr;
339         PropertyRNA *prop;
340         int index, success= 0;
341
342         uiContextActiveProperty(C, &ptr, &prop, &index);
343
344         if (ptr.data && prop) {
345                 CollectionPointerLink *link;
346                 ListBase lb;
347
348                 if(copy_to_selected_list(C, &ptr, &lb)) {
349                         for(link= lb.first; link; link=link->next)
350                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop))
351                                         success= 1;
352
353                         BLI_freelistN(&lb);
354                 }
355         }
356
357         return success;
358 }
359
360 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
361 {
362         PointerRNA ptr;
363         PropertyRNA *prop;
364         int success= 0;
365         int index, all = RNA_boolean_get(op->ptr, "all");
366
367         /* try to reset the nominated setting to its default value */
368         uiContextActiveProperty(C, &ptr, &prop, &index);
369         
370         /* if there is a valid property that is editable... */
371         if (ptr.data && prop) {
372                 CollectionPointerLink *link;
373                 ListBase lb;
374
375                 if(copy_to_selected_list(C, &ptr, &lb)) {
376                         for(link= lb.first; link; link=link->next) {
377                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop)) {
378                                         if(RNA_property_copy(&link->ptr, &ptr, prop, (all)? -1: index)) {
379                                                 RNA_property_update(C, &link->ptr, prop);
380                                                 success= 1;
381                                         }
382                                 }
383                         }
384
385                         BLI_freelistN(&lb);
386                 }
387         }
388         
389         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
390 }
391
392 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
393 {
394         /* identifiers */
395         ot->name= "Copy To Selected";
396         ot->idname= "UI_OT_copy_to_selected_button";
397         ot->description= "Copy property from this object to selected objects or bones";
398
399         /* callbacks */
400         ot->poll= copy_to_selected_button_poll;
401         ot->exec= copy_to_selected_button_exec;
402
403         /* flags */
404         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
405
406         /* properties */
407         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array.");
408 }
409
410 /* Reports to Textblock Operator ------------------------ */
411
412 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere 
413  * when there are too many to display...
414  */
415
416 static int reports_to_text_poll(bContext *C)
417 {
418         return CTX_wm_reports(C) != NULL;
419 }
420
421 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
422 {
423         ReportList *reports = CTX_wm_reports(C);
424         Text *txt;
425         char *str;
426         
427         /* create new text-block to write to */
428         txt = add_empty_text("Recent Reports");
429         
430         /* convert entire list to a display string, and add this to the text-block
431          *      - if commandline debug option enabled, show debug reports too
432          *      - otherwise, up to info (which is what users normally see)
433          */
434         str = BKE_reports_string(reports, (G.f & G_DEBUG)? RPT_DEBUG : RPT_INFO);
435         
436         write_text(txt, str);
437         MEM_freeN(str);
438         
439         return OPERATOR_FINISHED;
440 }
441
442 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
443 {
444         /* identifiers */
445         ot->name= "Reports to Text Block";
446         ot->idname= "UI_OT_reports_to_textblock";
447         ot->description= "Write the reports ";
448         
449         /* callbacks */
450         ot->poll= reports_to_text_poll;
451         ot->exec= reports_to_text_exec;
452 }
453
454 /* ********************************************************* */
455 /* Registration */
456
457 void UI_buttons_operatortypes(void)
458 {
459         WM_operatortype_append(UI_OT_eyedropper);
460         WM_operatortype_append(UI_OT_reset_default_theme);
461         WM_operatortype_append(UI_OT_copy_data_path_button);
462         WM_operatortype_append(UI_OT_reset_default_button);
463         WM_operatortype_append(UI_OT_copy_to_selected_button);
464         WM_operatortype_append(UI_OT_reports_to_textblock); // XXX: temp?
465 }
466