fix 2 bugs with reset-default failing on operators redo panel.
[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 "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_text.h" /* for UI_OT_reports_to_text */
50 #include "BKE_report.h"
51
52 #include "RNA_access.h"
53 #include "RNA_define.h"
54
55 #include "BIF_gl.h"
56
57 #include "UI_interface.h"
58
59 #include "interface_intern.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64
65
66 /* ********************************************************** */
67
68 typedef struct Eyedropper {
69         PointerRNA ptr;
70         PropertyRNA *prop;
71         int index;
72 } Eyedropper;
73
74 static int eyedropper_init(bContext *C, wmOperator *op)
75 {
76         Eyedropper *eye;
77         
78         op->customdata= eye= MEM_callocN(sizeof(Eyedropper), "Eyedropper");
79         
80         uiContextActiveProperty(C, &eye->ptr, &eye->prop, &eye->index);
81         
82         return (eye->ptr.data && eye->prop && RNA_property_editable(&eye->ptr, eye->prop));
83 }
84  
85 static void eyedropper_exit(bContext *C, wmOperator *op)
86 {
87         WM_cursor_restore(CTX_wm_window(C));
88         
89         if(op->customdata)
90                 MEM_freeN(op->customdata);
91         op->customdata= NULL;
92 }
93
94 static int eyedropper_cancel(bContext *C, wmOperator *op)
95 {
96         eyedropper_exit(C, op);
97         return OPERATOR_CANCELLED;
98 }
99
100 static void eyedropper_sample(bContext *C, Eyedropper *eye, int mx, int my)
101 {
102         if(RNA_property_type(eye->prop) == PROP_FLOAT) {
103                 const int color_manage = CTX_data_scene(C)->r.color_mgt_flag & R_COLOR_MANAGEMENT;
104                 float col[4];
105         
106                 RNA_property_float_get_array(&eye->ptr, eye->prop, col);
107                 
108                 glReadBuffer(GL_FRONT);
109                 glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, col);
110                 glReadBuffer(GL_BACK);
111         
112                 if (RNA_property_array_length(&eye->ptr, eye->prop) < 3) return;
113
114                 /* convert from screen (srgb) space to linear rgb space */
115                 if (color_manage && RNA_property_subtype(eye->prop) == PROP_COLOR)
116                         srgb_to_linearrgb_v3_v3(col, col);
117                 
118                 RNA_property_float_set_array(&eye->ptr, eye->prop, col);
119                 
120                 RNA_property_update(C, &eye->ptr, eye->prop);
121         }
122 }
123
124 /* main modal status check */
125 static int eyedropper_modal(bContext *C, wmOperator *op, wmEvent *event)
126 {
127         Eyedropper *eye = (Eyedropper *)op->customdata;
128         
129         switch(event->type) {
130                 case ESCKEY:
131                 case RIGHTMOUSE:
132                         return eyedropper_cancel(C, op);
133                 case LEFTMOUSE:
134                         if(event->val==KM_RELEASE) {
135                                 eyedropper_sample(C, eye, event->x, event->y);
136                                 eyedropper_exit(C, op);
137                                 return OPERATOR_FINISHED;
138                         }
139                         break;
140         }
141         
142         return OPERATOR_RUNNING_MODAL;
143 }
144
145 /* Modal Operator init */
146 static int eyedropper_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
147 {
148         /* init */
149         if (eyedropper_init(C, op)) {
150                 WM_cursor_modal(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
151
152                 /* add temp handler */
153                 WM_event_add_modal_handler(C, op);
154                 
155                 return OPERATOR_RUNNING_MODAL;
156         } else {
157                 eyedropper_exit(C, op);
158                 return OPERATOR_CANCELLED;
159         }
160 }
161
162 /* Repeat operator */
163 static int eyedropper_exec (bContext *C, wmOperator *op)
164 {
165         /* init */
166         if (eyedropper_init(C, op)) {
167                 
168                 /* do something */
169                 
170                 /* cleanup */
171                 eyedropper_exit(C, op);
172                 
173                 return OPERATOR_FINISHED;
174         } else {
175                 return OPERATOR_CANCELLED;
176         }
177 }
178
179 static int eyedropper_poll(bContext *C)
180 {
181         if (!CTX_wm_window(C)) return 0;
182         else return 1;
183 }
184
185 static void UI_OT_eyedropper(wmOperatorType *ot)
186 {
187         /* identifiers */
188         ot->name= "Eyedropper";
189         ot->idname= "UI_OT_eyedropper";
190         ot->description= "Sample a color from the Blender Window to store in a property";
191         
192         /* api callbacks */
193         ot->invoke= eyedropper_invoke;
194         ot->modal= eyedropper_modal;
195         ot->cancel= eyedropper_cancel;
196         ot->exec= eyedropper_exec;
197         ot->poll= eyedropper_poll;
198         
199         /* flags */
200         ot->flag= OPTYPE_BLOCKING;
201         
202         /* properties */
203 }
204
205 /* Reset Default Theme ------------------------ */
206
207 static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
208 {
209         ui_theme_init_default();
210         WM_event_add_notifier(C, NC_WINDOW, NULL);
211         
212         return OPERATOR_FINISHED;
213 }
214
215 static void UI_OT_reset_default_theme(wmOperatorType *ot)
216 {
217         /* identifiers */
218         ot->name= "Reset to Default Theme";
219         ot->idname= "UI_OT_reset_default_theme";
220         ot->description= "Reset to the default theme colors";
221         
222         /* callbacks */
223         ot->exec= reset_default_theme_exec;
224         
225         /* flags */
226         ot->flag= OPTYPE_REGISTER;
227 }
228
229 /* Copy Data Path Operator ------------------------ */
230
231 static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
232 {
233         PointerRNA ptr;
234         PropertyRNA *prop;
235         char *path;
236         int success= 0;
237         int index;
238
239         /* try to create driver using property retrieved from UI */
240         uiContextActiveProperty(C, &ptr, &prop, &index);
241
242         if (ptr.id.data && ptr.data && prop) {
243                 path= RNA_path_from_ID_to_property(&ptr, prop);
244                 
245                 if (path) {
246                         WM_clipboard_text_set(path, FALSE);
247                         MEM_freeN(path);
248                 }
249         }
250
251         /* since we're just copying, we don't really need to do anything else...*/
252         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
253 }
254
255 static void UI_OT_copy_data_path_button(wmOperatorType *ot)
256 {
257         /* identifiers */
258         ot->name= "Copy Data Path";
259         ot->idname= "UI_OT_copy_data_path_button";
260         ot->description= "Copy the RNA data path for this property to the clipboard";
261
262         /* callbacks */
263         ot->exec= copy_data_path_button_exec;
264         //op->poll= ??? // TODO: need to have some valid property before this can be done
265
266         /* flags */
267         ot->flag= OPTYPE_REGISTER;
268 }
269
270 /* Reset to Default Values Button Operator ------------------------ */
271
272 static int reset_default_button_poll(bContext *C)
273 {
274         PointerRNA ptr;
275         PropertyRNA *prop;
276         int index;
277
278         uiContextActiveProperty(C, &ptr, &prop, &index);
279         
280         return (ptr.data && prop && RNA_property_editable(&ptr, prop));
281 }
282
283 static int reset_default_button_exec(bContext *C, wmOperator *op)
284 {
285         PointerRNA ptr;
286         PropertyRNA *prop;
287         int success= 0;
288         int index, all = RNA_boolean_get(op->ptr, "all");
289
290         /* try to reset the nominated setting to its default value */
291         uiContextActiveProperty(C, &ptr, &prop, &index);
292         
293         /* if there is a valid property that is editable... */
294         if (ptr.data && prop && RNA_property_editable(&ptr, prop)) {
295                 if(RNA_property_reset(&ptr, prop, (all)? -1: index)) {
296                         /* perform updates required for this property */
297                         RNA_property_update(C, &ptr, prop);
298
299                         /* as if we pressed the button */
300                         uiContextActivePropertyHandle(C);
301
302                         success= 1;
303                 }
304         }
305
306         /* Since we dont want to undo _all_ edits to settings, eg window
307          * edits on the screen or on operator settings.
308          * it might be better to move undo's inline - campbell */
309         /* Note that buttons already account for this, it might be better to
310          * have a way to edit the buttons rather than set the rna since block
311          * callbacks also fail to run. */
312         if(success) {
313                 ID *id= ptr.id.data;
314                 if(id && ID_CHECK_UNDO(id)) {
315                         /* do nothing, go ahead with undo */
316                 }
317                 else {
318                         return OPERATOR_CANCELLED;
319                 }
320         }
321         /* end hack */
322
323         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
324 }
325
326 static void UI_OT_reset_default_button(wmOperatorType *ot)
327 {
328         /* identifiers */
329         ot->name= "Reset to Default Value";
330         ot->idname= "UI_OT_reset_default_button";
331         ot->description= "Reset this property's value to its default value";
332
333         /* callbacks */
334         ot->poll= reset_default_button_poll;
335         ot->exec= reset_default_button_exec;
336
337         /* flags */
338         ot->flag= OPTYPE_UNDO;
339         
340         /* properties */
341         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
342 }
343
344 /* Copy To Selected Operator ------------------------ */
345
346 static int copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb)
347 {
348         if(RNA_struct_is_a(ptr->type, &RNA_Object))
349                 *lb = CTX_data_collection_get(C, "selected_editable_objects");
350         else if(RNA_struct_is_a(ptr->type, &RNA_EditBone))
351                 *lb = CTX_data_collection_get(C, "selected_editable_bones");
352         else if(RNA_struct_is_a(ptr->type, &RNA_PoseBone))
353                 *lb = CTX_data_collection_get(C, "selected_pose_bones");
354         else if(RNA_struct_is_a(ptr->type, &RNA_Sequence))
355                 *lb = CTX_data_collection_get(C, "selected_editable_sequences");
356         else
357                 return 0;
358         
359         return 1;
360 }
361
362 static int copy_to_selected_button_poll(bContext *C)
363 {
364         PointerRNA ptr;
365         PropertyRNA *prop;
366         int index, success= 0;
367
368         uiContextActiveProperty(C, &ptr, &prop, &index);
369
370         if (ptr.data && prop) {
371                 CollectionPointerLink *link;
372                 ListBase lb;
373
374                 if(copy_to_selected_list(C, &ptr, &lb)) {
375                         for(link= lb.first; link; link=link->next)
376                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop))
377                                         success= 1;
378
379                         BLI_freelistN(&lb);
380                 }
381         }
382
383         return success;
384 }
385
386 static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
387 {
388         PointerRNA ptr;
389         PropertyRNA *prop;
390         int success= 0;
391         int index, all = RNA_boolean_get(op->ptr, "all");
392
393         /* try to reset the nominated setting to its default value */
394         uiContextActiveProperty(C, &ptr, &prop, &index);
395         
396         /* if there is a valid property that is editable... */
397         if (ptr.data && prop) {
398                 CollectionPointerLink *link;
399                 ListBase lb;
400
401                 if(copy_to_selected_list(C, &ptr, &lb)) {
402                         for(link= lb.first; link; link=link->next) {
403                                 if(link->ptr.data != ptr.data && RNA_property_editable(&link->ptr, prop)) {
404                                         if(RNA_property_copy(&link->ptr, &ptr, prop, (all)? -1: index)) {
405                                                 RNA_property_update(C, &link->ptr, prop);
406                                                 success= 1;
407                                         }
408                                 }
409                         }
410
411                         BLI_freelistN(&lb);
412                 }
413         }
414         
415         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
416 }
417
418 static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
419 {
420         /* identifiers */
421         ot->name= "Copy To Selected";
422         ot->idname= "UI_OT_copy_to_selected_button";
423         ot->description= "Copy property from this object to selected objects or bones";
424
425         /* callbacks */
426         ot->poll= copy_to_selected_button_poll;
427         ot->exec= copy_to_selected_button_exec;
428
429         /* flags */
430         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
431
432         /* properties */
433         RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
434 }
435
436 /* Reports to Textblock Operator ------------------------ */
437
438 /* FIXME: this is just a temporary operator so that we can see all the reports somewhere 
439  * when there are too many to display...
440  */
441
442 static int reports_to_text_poll(bContext *C)
443 {
444         return CTX_wm_reports(C) != NULL;
445 }
446
447 static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op))
448 {
449         ReportList *reports = CTX_wm_reports(C);
450         Text *txt;
451         char *str;
452         
453         /* create new text-block to write to */
454         txt = add_empty_text("Recent Reports");
455         
456         /* convert entire list to a display string, and add this to the text-block
457          *      - if commandline debug option enabled, show debug reports too
458          *      - otherwise, up to info (which is what users normally see)
459          */
460         str = BKE_reports_string(reports, (G.f & G_DEBUG)? RPT_DEBUG : RPT_INFO);
461         
462         write_text(txt, str);
463         MEM_freeN(str);
464         
465         return OPERATOR_FINISHED;
466 }
467
468 static void UI_OT_reports_to_textblock(wmOperatorType *ot)
469 {
470         /* identifiers */
471         ot->name= "Reports to Text Block";
472         ot->idname= "UI_OT_reports_to_textblock";
473         ot->description= "Write the reports ";
474         
475         /* callbacks */
476         ot->poll= reports_to_text_poll;
477         ot->exec= reports_to_text_exec;
478 }
479
480 /* ********************************************************* */
481 /* Registration */
482
483 void UI_buttons_operatortypes(void)
484 {
485         WM_operatortype_append(UI_OT_eyedropper);
486         WM_operatortype_append(UI_OT_reset_default_theme);
487         WM_operatortype_append(UI_OT_copy_data_path_button);
488         WM_operatortype_append(UI_OT_reset_default_button);
489         WM_operatortype_append(UI_OT_copy_to_selected_button);
490         WM_operatortype_append(UI_OT_reports_to_textblock); // XXX: temp?
491 }
492