Manual merge of soc-2009-kazanbas branch:
[blender.git] / source / blender / editors / space_graph / graph_buttons.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  * 
24  * Contributor(s): Blender Foundation, Joshua Leung
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_anim_types.h"
35 #include "DNA_action_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_userdef_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_arithb.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_editVert.h"
47 #include "BLI_rand.h"
48
49 #include "BKE_action.h"
50 #include "BKE_animsys.h"
51 #include "BKE_context.h"
52 #include "BKE_curve.h"
53 #include "BKE_customdata.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_fcurve.h"
56 #include "BKE_library.h"
57 #include "BKE_main.h"
58 #include "BKE_object.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_utildefines.h"
62
63 #include "BIF_gl.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "RNA_access.h"
69 #include "RNA_define.h"
70
71 #include "ED_anim_api.h"
72 #include "ED_keyframing.h"
73 #include "ED_screen.h"
74 #include "ED_types.h"
75 #include "ED_util.h"
76
77 #include "UI_interface.h"
78 #include "UI_resources.h"
79 #include "UI_view2d.h"
80
81 #include "graph_intern.h"       // own include
82
83 /* XXX */
84
85 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
86 #define UI_FLT_MAX      10000.0f
87
88
89 /* ******************* graph editor space & buttons ************** */
90
91 #define B_NOP           1
92 #define B_REDR          2
93
94 /* -------------- */
95
96 static void do_graph_region_buttons(bContext *C, void *arg, int event)
97 {
98         //Scene *scene= CTX_data_scene(C);
99         
100         switch(event) {
101
102         }
103         
104         /* default for now */
105         //WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
106 }
107
108 static int graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
109 {
110         bAnimContext ac;
111         bAnimListElem *elem= NULL;
112         
113         /* for now, only draw if we could init the anim-context info (necessary for all animation-related tools) 
114          * to work correctly is able to be correctly retrieved. There's no point showing empty panels?
115          */
116         if (ANIM_animdata_get_context(C, &ac) == 0) 
117                 return 0;
118         
119         /* try to find 'active' F-Curve */
120         elem= get_active_fcurve_channel(&ac);
121         if(elem == NULL) 
122                 return 0;
123         
124         if(fcu)
125                 *fcu= (FCurve*)elem->data;
126         if(ale)
127                 *ale= elem;
128         else
129                 MEM_freeN(elem);
130         
131         return 1;
132 }
133
134 static int graph_panel_poll(const bContext *C, PanelType *pt)
135 {
136         return graph_panel_context(C, NULL, NULL);
137 }
138
139 static void graph_panel_properties(const bContext *C, Panel *pa)
140 {
141         bAnimListElem *ale;
142         FCurve *fcu;
143         uiBlock *block;
144         char name[128];
145
146         if(!graph_panel_context(C, &ale, &fcu))
147                 return;
148
149         block= uiLayoutFreeBlock(pa->layout);
150         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
151
152         /* Info - Active F-Curve */
153         uiDefBut(block, LABEL, 1, "Active F-Curve:",                                    10, 200, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
154         
155         if (ale->id) { 
156                 // icon of active blocktype - is this really necessary?
157                 int icon= geticon_anim_blocktype(GS(ale->id->name));
158                 
159                 // xxx type of icon-but is currently "LABEL", as that one is plain...
160                 uiDefIconBut(block, LABEL, 1, icon, 10, 180, 20, 19, NULL, 0, 0, 0, 0, "ID-type that F-Curve belongs to");
161         }
162         
163         getname_anim_fcurve(name, ale->id, fcu);
164         uiDefBut(block, LABEL, 1, name, 40, 180, 300, 19, NULL, 0.0, 0.0, 0, 0, "Name of Active F-Curve");
165         
166         /* TODO: the following settings could be added here
167          *      - F-Curve coloring mode - mode selector + color selector
168          *      - Access details (ID-block + RNA-Path + Array Index)
169          *      - ...
170          */
171
172         MEM_freeN(ale);
173 }
174
175 /* ******************* drivers ******************************** */
176
177 #define B_IPO_DEPCHANGE         10
178
179 static void do_graph_region_driver_buttons(bContext *C, void *arg, int event)
180 {
181         Scene *scene= CTX_data_scene(C);
182         
183         switch (event) {
184                 case B_IPO_DEPCHANGE:
185                 {
186                         /* rebuild depsgraph for the new deps */
187                         DAG_scene_sort(scene);
188                         
189                         /* force an update of depsgraph */
190                         ED_anim_dag_flush_update(C);
191                 }
192                         break;
193         }
194         
195         /* default for now */
196         WM_event_add_notifier(C, NC_SCENE, scene);
197 }
198
199 /* callback to remove the active driver */
200 static void driver_remove_cb (bContext *C, void *ale_v, void *dummy_v)
201 {
202         bAnimListElem *ale= (bAnimListElem *)ale_v;
203         ID *id= ale->id;
204         FCurve *fcu= ale->data;
205         
206         /* try to get F-Curve that driver lives on, and ID block which has this AnimData */
207         if (ELEM(NULL, id, fcu))
208                 return;
209         
210         /* call API method to remove this driver  */    
211         ANIM_remove_driver(id, fcu->rna_path, fcu->array_index, 0);
212 }
213
214 /* callback to add a target variable to the active driver */
215 static void driver_add_var_cb (bContext *C, void *driver_v, void *dummy_v)
216 {
217         ChannelDriver *driver= (ChannelDriver *)driver_v;
218         
219         /* add a new var */
220         driver_add_new_target(driver);
221 }
222
223 /* callback to remove target variable from active driver */
224 static void driver_delete_var_cb (bContext *C, void *driver_v, void *dtar_v)
225 {
226         ChannelDriver *driver= (ChannelDriver *)driver_v;
227         DriverTarget *dtar= (DriverTarget *)dtar_v;
228         
229         /* add a new var */
230         driver_free_target(driver, dtar);
231 }
232
233 /* callback to reset the driver's flags */
234 static void driver_update_flags_cb (bContext *C, void *fcu_v, void *dummy_v)
235 {
236         FCurve *fcu= (FCurve *)fcu_v;
237         ChannelDriver *driver= fcu->driver;
238         
239         /* clear invalid flags */
240         driver->flag &= ~DRIVER_FLAG_INVALID;
241 }
242
243 /* drivers panel poll */
244 static int graph_panel_drivers_poll(const bContext *C, PanelType *pt)
245 {
246         SpaceIpo *sipo= CTX_wm_space_graph(C);
247
248         if(sipo->mode != SIPO_MODE_DRIVERS)
249                 return 0;
250
251         return graph_panel_context(C, NULL, NULL);
252 }
253
254 static void test_obpoin_but(struct bContext *C, char *name, ID **idpp)
255 {
256         ID *id;
257         
258         id= CTX_data_main(C)->object.first;
259         while(id) {
260                 if( strcmp(name, id->name+2)==0 ) {
261                         *idpp= id;
262                         id_lib_extern(id);      /* checks lib data, sets correct flag for saving then */
263                         return;
264                 }
265                 id= id->next;
266         }
267         *idpp= NULL;
268 }
269
270 /* driver settings for active F-Curve (only for 'Drivers' mode) */
271 static void graph_panel_drivers(const bContext *C, Panel *pa)
272 {
273         bAnimListElem *ale;
274         FCurve *fcu;
275         ChannelDriver *driver;
276         DriverTarget *dtar;
277         
278         PointerRNA rna_ptr;
279         uiBlock *block;
280         uiBut *but;
281         int yco=85, i=0;
282
283         if(!graph_panel_context(C, &ale, &fcu))
284                 return;
285
286         driver= fcu->driver;
287         
288         block= uiLayoutFreeBlock(pa->layout);
289         uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL);
290         
291         /* general actions */
292         but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Update Dependencies", 10, 200, 180, 22, NULL, 0.0, 0.0, 0, 0, "Force updates of dependencies");
293         uiButSetFunc(but, driver_update_flags_cb, fcu, NULL);
294         
295         but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Remove Driver", 200, 200, 110, 18, NULL, 0.0, 0.0, 0, 0, "Remove this driver");
296         uiButSetFunc(but, driver_remove_cb, ale, NULL);
297         
298         /* type */
299         uiDefBut(block, LABEL, 1, "Type:",                                      10, 170, 60, 20, NULL, 0.0, 0.0, 0, 0, "");
300         uiDefButI(block, MENU, B_IPO_DEPCHANGE,
301                                         "Driver Type%t|Normal%x0|Scripted Expression%x1|Rotational Difference%x2", 
302                                         70,170,240,20, &driver->type, 0, 0, 0, 0, "Driver type");
303         
304         /* show expression box if doing scripted drivers */
305         if (driver->type == DRIVER_TYPE_PYTHON) {
306                 uiDefBut(block, TEX, B_REDR, "Expr: ", 10,150,300,20, driver->expression, 0, 255, 0, 0, "One-liner Python Expression to use as Scripted Expression");
307                 
308                 /* errors */
309                 if (driver->flag & DRIVER_FLAG_INVALID) {
310                         uiDefIconBut(block, LABEL, 1, ICON_ERROR, 10, 130, 48, 48, NULL, 0, 0, 0, 0, ""); // a bit larger
311                         uiDefBut(block, LABEL, 0, "Error: invalid Python expression",
312                                         50,110,230,19, NULL, 0, 0, 0, 0, "");
313                 }
314         }
315         else {
316                 /* errors */
317                 if (driver->flag & DRIVER_FLAG_INVALID) {
318                         uiDefIconBut(block, LABEL, 1, ICON_ERROR, 10, 130, 48, 48, NULL, 0, 0, 0, 0, ""); // a bit larger
319                         uiDefBut(block, LABEL, 0, "Error: invalid target channel(s)",
320                                         50,130,230,19, NULL, 0, 0, 0, 0, "");
321                 }
322         }
323         
324         but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Add Variable", 10, 110, 300, 20, NULL, 0.0, 0.0, 0, 0, "Add a new target variable for this Driver");
325         uiButSetFunc(but, driver_add_var_cb, driver, NULL);
326         
327         /* loop over targets, drawing them */
328         for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
329                 short height = (dtar->id) ? 80 : 60;
330                 
331                 /* panel behind buttons */
332                 uiDefBut(block, ROUNDBOX, B_REDR, "", 5, yco-height+25, 310, height, NULL, 5.0, 0.0, 12.0, 0, "");
333                 
334                 /* variable name */
335                 uiDefButC(block, TEX, B_REDR, "Name: ", 10,yco,280,20, dtar->name, 0, 63, 0, 0, "Name of target variable (No spaces or dots are allowed. Also, must not start with a symbol or digit).");
336                 
337                 /* remove button */
338                 but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 290, yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete target variable.");
339                 uiButSetFunc(but, driver_delete_var_cb, driver, dtar);
340                 
341                 
342                 /* Target Object */
343                 uiDefBut(block, LABEL, 1, "Value:",     10, yco-30, 60, 20, NULL, 0.0, 0.0, 0, 0, "");
344                 uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_REDR, "Ob: ", 70, yco-30, 240, 20, &dtar->id, "Object to use as Driver target");
345                 
346                 // XXX should we hide these technical details?
347                 if (dtar->id) {
348                         uiBlockBeginAlign(block);
349                                 /* RNA Path */
350                                 RNA_pointer_create(ale->id, &RNA_DriverTarget, dtar, &rna_ptr);
351                                 uiDefButR(block, TEX, 0, "Path: ", 10, yco-50, 250, 20, &rna_ptr, "rna_path", 0, 0, 0, -1, -1, "RNA Path (from Driver Object) to property used as Driver.");
352                                         
353                                 /* Array Index */
354                                 uiDefButI(block, NUM, B_REDR, "", 260,yco-50,50,20, &dtar->array_index, 0, INT_MAX, 0, 0, "Index to the specific property used as Driver if applicable.");
355                         uiBlockEndAlign(block);
356                 }
357                 
358                 /* adjust y-coordinate for next target */
359                 yco -= height;
360                 i++;
361         }
362
363         MEM_freeN(ale);
364 }
365
366 /* ******************* f-modifiers ******************************** */
367 /* all the drawing code is in editors/animation/fmodifier_ui.c */
368
369 #define B_FMODIFIER_REDRAW              20
370
371 static void do_graph_region_modifier_buttons(bContext *C, void *arg, int event)
372 {
373         switch (event) {
374                 case B_REDR:
375                 case B_FMODIFIER_REDRAW: // XXX this should send depsgraph updates too
376                         ED_area_tag_redraw(CTX_wm_area(C));
377                         return; /* no notifier! */
378         }
379 }
380
381 static void graph_panel_modifiers(const bContext *C, Panel *pa) 
382 {
383         bAnimListElem *ale;
384         FCurve *fcu;
385         FModifier *fcm;
386         uiLayout *col, *row;
387         uiBlock *block;
388         
389         if (!graph_panel_context(C, &ale, &fcu))
390                 return;
391         
392         block= uiLayoutGetBlock(pa->layout);
393         uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
394         
395         /* 'add modifier' button at top of panel */
396         {
397                 row= uiLayoutRow(pa->layout, 0);
398                 block= uiLayoutGetBlock(row);
399                 
400                 // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
401                 uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve");
402         }
403         
404         /* draw each modifier */
405         for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
406                 col= uiLayoutColumn(pa->layout, 1);
407                 
408                 ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
409         }
410
411         MEM_freeN(ale);
412 }
413
414 /* ******************* general ******************************** */
415
416 void graph_buttons_register(ARegionType *art)
417 {
418         PanelType *pt;
419
420         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
421         strcpy(pt->idname, "GRAPH_PT_properties");
422         strcpy(pt->label, "Properties");
423         pt->draw= graph_panel_properties;
424         pt->poll= graph_panel_poll;
425         BLI_addtail(&art->paneltypes, pt);
426
427         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
428         strcpy(pt->idname, "GRAPH_PT_drivers");
429         strcpy(pt->label, "Drivers");
430         pt->draw= graph_panel_drivers;
431         pt->poll= graph_panel_drivers_poll;
432         BLI_addtail(&art->paneltypes, pt);
433
434         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
435         strcpy(pt->idname, "GRAPH_PT_modifiers");
436         strcpy(pt->label, "Modifiers");
437         pt->draw= graph_panel_modifiers;
438         pt->poll= graph_panel_poll;
439         BLI_addtail(&art->paneltypes, pt);
440 }
441
442 static int graph_properties(bContext *C, wmOperator *op)
443 {
444         ScrArea *sa= CTX_wm_area(C);
445         ARegion *ar= graph_has_buttons_region(sa);
446         
447         if(ar)
448                 ED_region_toggle_hidden(C, ar);
449
450         return OPERATOR_FINISHED;
451 }
452
453 void GRAPH_OT_properties(wmOperatorType *ot)
454 {
455         ot->name= "Properties";
456         ot->idname= "GRAPH_OT_properties";
457         
458         ot->exec= graph_properties;
459         ot->poll= ED_operator_ipo_active; // xxx
460         
461         /* flags */
462         ot->flag= 0;
463 }