568c76f3dfc8122738c1eb26b8c333554bcd07ab
[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., 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  * 
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_object_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_math.h"
41 #include "BLI_blenlib.h"
42 #include "BLI_editVert.h"
43 #include "BLI_rand.h"
44
45 #include "BKE_context.h"
46 #include "BKE_depsgraph.h"
47 #include "BKE_fcurve.h"
48 #include "BKE_main.h"
49 #include "BKE_screen.h"
50
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "RNA_access.h"
56
57 #include "ED_anim_api.h"
58 #include "ED_keyframing.h"
59 #include "ED_screen.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63
64 #include "graph_intern.h"       // own include
65
66 /* XXX */
67
68 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
69 #define UI_FLT_MAX      10000.0f
70
71
72 /* ******************* graph editor space & buttons ************** */
73
74 #define B_NOP           1
75 #define B_REDR          2
76
77 /* -------------- */
78
79 static void do_graph_region_buttons(bContext *C, void *arg, int event)
80 {
81         //Scene *scene= CTX_data_scene(C);
82         
83         switch(event) {
84
85         }
86         
87         /* default for now */
88         //WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
89 }
90
91 /* -------------- */
92
93 static int graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
94 {
95         bAnimContext ac;
96         bAnimListElem *elem= NULL;
97         
98         /* for now, only draw if we could init the anim-context info (necessary for all animation-related tools) 
99          * to work correctly is able to be correctly retrieved. There's no point showing empty panels?
100          */
101         if (ANIM_animdata_get_context(C, &ac) == 0) 
102                 return 0;
103         
104         /* try to find 'active' F-Curve */
105         elem= get_active_fcurve_channel(&ac);
106         if(elem == NULL) 
107                 return 0;
108         
109         if(fcu)
110                 *fcu= (FCurve*)elem->data;
111         if(ale)
112                 *ale= elem;
113         else
114                 MEM_freeN(elem);
115         
116         return 1;
117 }
118
119 static int graph_panel_poll(const bContext *C, PanelType *pt)
120 {
121         return graph_panel_context(C, NULL, NULL);
122 }
123
124 /* -------------- */
125
126 /* Graph Editor View Settings */
127 static void graph_panel_view(const bContext *C, Panel *pa)
128 {
129         bScreen *sc= CTX_wm_screen(C);
130         SpaceIpo *sipo= CTX_wm_space_graph(C);
131         Scene *scene= CTX_data_scene(C);
132         PointerRNA spaceptr, sceneptr;
133         uiLayout *col, *subcol, *row;
134         
135         /* get RNA pointers for use when creating the UI elements */
136         RNA_id_pointer_create(&scene->id, &sceneptr);
137         RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
138
139         /* 2D-Cursor */
140         col= uiLayoutColumn(pa->layout, 0);
141                 uiItemR(col, &spaceptr, "show_cursor", 0, NULL, 0);
142                 
143                 subcol= uiLayoutColumn(col, 1);
144                 uiLayoutSetActive(subcol, RNA_boolean_get(&spaceptr, "show_cursor")); 
145                         uiItemO(subcol, "Cursor from Selection", 0, "GRAPH_OT_frame_jump");
146                 
147                 subcol= uiLayoutColumn(col, 1);
148                 uiLayoutSetActive(subcol, RNA_boolean_get(&spaceptr, "show_cursor")); 
149                         row= uiLayoutSplit(subcol, 0.7, 1);
150                                 uiItemR(row, &sceneptr, "frame_current", 0, "Cursor X", 0);
151                                 uiItemEnumO(row, "GRAPH_OT_snap", "To Keys", 0, "type", GRAPHKEYS_SNAP_CFRA);
152                         row= uiLayoutSplit(subcol, 0.7, 1);
153                                 uiItemR(row, &spaceptr, "cursor_position_y", 0, "Cursor Y", 0);
154                                 uiItemEnumO(row, "GRAPH_OT_snap", "To Keys", 0, "type", GRAPHKEYS_SNAP_VALUE);
155 }
156
157 /* ******************* active F-Curve ************** */
158
159 static void graph_panel_properties(const bContext *C, Panel *pa)
160 {
161         bAnimListElem *ale;
162         FCurve *fcu;
163         PointerRNA fcu_ptr;
164         uiLayout *layout = pa->layout;
165         uiLayout *col, *row, *subrow;
166         uiBlock *block;
167         char name[256];
168         int icon = 0;
169
170         if (!graph_panel_context(C, &ale, &fcu))
171                 return;
172         
173         block= uiLayoutGetBlock(layout);
174         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
175         
176         /* F-Curve pointer */
177         RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
178         
179         /* user-friendly 'name' for F-Curve */
180         // TODO: only show the path if this is invalid?
181         col= uiLayoutColumn(layout, 0);
182                 icon= getname_anim_fcurve(name, ale->id, fcu);
183                 uiItemL(col, name, icon);
184                 
185         /* RNA-Path Editing - only really should be enabled when things aren't working */
186         col= uiLayoutColumn(layout, 1);
187                 uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED)!=0); 
188                 uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
189                 uiItemR(col, &fcu_ptr, "array_index", 0, NULL, 0);
190                 
191         /* color settings */
192         col= uiLayoutColumn(layout, 1);
193                 uiItemL(col, "Display Color:", 0);
194                 
195                 row= uiLayoutRow(col, 1);
196                         uiItemR(row, &fcu_ptr, "color_mode", 0, "", 0);
197                         
198                         subrow= uiLayoutRow(row, 1);
199                                 uiLayoutSetEnabled(subrow, (fcu->color_mode==FCURVE_COLOR_CUSTOM));
200                                 uiItemR(subrow, &fcu_ptr, "color", 0, "", 0);
201         
202         MEM_freeN(ale);
203 }
204
205 /* ******************* active Keyframe ************** */
206
207 /* get 'active' keyframe for panel editing */
208 static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezTriple **prevbezt)
209 {
210         BezTriple *b;
211         int i;
212         
213         /* zero the pointers */
214         *bezt = *prevbezt = NULL;
215         
216         /* sanity checks */
217         if ((fcu->bezt == NULL) || (fcu->totvert == 0))
218                 return 0;
219                 
220         /* find first selected keyframe for now, and call it the active one 
221          *      - this is a reasonable assumption, given that whenever anyone 
222          *        wants to edit numerically, there is likely to only be 1 vert selected
223          */
224         for (i=0, b=fcu->bezt; i < fcu->totvert; i++, b++) {
225                 if (BEZSELECTED(b)) {
226                         /* found 
227                          *      - 'previous' is either the one before, of the keyframe itself (which is still fine)
228                          *              XXX: we can just make this null instead if needed
229                          */
230                         *prevbezt = (i > 0) ? b-1 : b;
231                         *bezt = b;
232                         
233                         return 1;
234                 }
235         }
236         
237         /* not found */
238         return 0;
239 }
240
241 static void graph_panel_key_properties(const bContext *C, Panel *pa)
242 {
243         bAnimListElem *ale;
244         FCurve *fcu;
245         BezTriple *bezt, *prevbezt;
246         
247         uiLayout *layout = pa->layout;
248         uiLayout *col;
249         uiBlock *block;
250
251         if (!graph_panel_context(C, &ale, &fcu))
252                 return;
253         
254         block = uiLayoutGetBlock(layout);
255         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
256         
257         /* only show this info if there are keyframes to edit */
258         if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
259                 PointerRNA bezt_ptr;
260                 
261                 /* RNA pointer to keyframe, to allow editing */
262                 RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr);
263                 
264                 /* interpolation */
265                 col= uiLayoutColumn(layout, 0);
266                         uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, 0);
267                         
268                 /* numerical coordinate editing */
269                 col= uiLayoutColumn(layout, 1);
270                         /* keyframe itself */
271                         uiItemR(col, &bezt_ptr, "co", 0, "Key", 0);
272                         
273                         /* previous handle - only if previous was Bezier interpolation */
274                         if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ))
275                                 uiItemR(col, &bezt_ptr, "handle_left", 0, NULL, 0);
276                         
277                         /* next handle - only if current is Bezier interpolation */
278                         if (bezt->ipo == BEZT_IPO_BEZ)
279                                 uiItemR(col, &bezt_ptr, "handle_right", 0, NULL, 0);
280         }
281         else
282                 uiItemL(layout, "No active keyframe on F-Curve", 0);
283         
284         MEM_freeN(ale);
285 }
286
287 /* ******************* drivers ******************************** */
288
289 #define B_IPO_DEPCHANGE         10
290
291 static void do_graph_region_driver_buttons(bContext *C, void *arg, int event)
292 {
293         Main *bmain= CTX_data_main(C);
294         Scene *scene= CTX_data_scene(C);
295         
296         switch (event) {
297                 case B_IPO_DEPCHANGE:
298                 {
299                         /* rebuild depsgraph for the new deps */
300                         DAG_scene_sort(bmain, scene);
301                         
302                         /* force an update of depsgraph */
303                         DAG_ids_flush_update(bmain, 0);
304                 }
305                         break;
306         }
307         
308         /* default for now */
309         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); // XXX could use better notifier
310 }
311
312 /* callback to remove the active driver */
313 static void driver_remove_cb (bContext *C, void *ale_v, void *dummy_v)
314 {
315         bAnimListElem *ale= (bAnimListElem *)ale_v;
316         ID *id= ale->id;
317         FCurve *fcu= ale->data;
318         
319         /* try to get F-Curve that driver lives on, and ID block which has this AnimData */
320         if (ELEM(NULL, id, fcu))
321                 return;
322         
323         /* call API method to remove this driver  */    
324         ANIM_remove_driver(id, fcu->rna_path, fcu->array_index, 0);
325 }
326
327 /* callback to add a target variable to the active driver */
328 static void driver_add_var_cb (bContext *C, void *driver_v, void *dummy_v)
329 {
330         ChannelDriver *driver= (ChannelDriver *)driver_v;
331         
332         /* add a new variable */
333         driver_add_new_variable(driver);
334 }
335
336 /* callback to remove target variable from active driver */
337 static void driver_delete_var_cb (bContext *C, void *driver_v, void *dvar_v)
338 {
339         ChannelDriver *driver= (ChannelDriver *)driver_v;
340         DriverVar *dvar= (DriverVar *)dvar_v;
341         
342         /* remove the active variable */
343         driver_free_variable(driver, dvar);
344 }
345
346 /* callback to reset the driver's flags */
347 static void driver_update_flags_cb (bContext *C, void *fcu_v, void *dummy_v)
348 {
349         FCurve *fcu= (FCurve *)fcu_v;
350         ChannelDriver *driver= fcu->driver;
351         
352         /* clear invalid flags */
353         fcu->flag &= ~FCURVE_DISABLED; // XXX?
354         driver->flag &= ~DRIVER_FLAG_INVALID;
355 }
356
357 /* drivers panel poll */
358 static int graph_panel_drivers_poll(const bContext *C, PanelType *pt)
359 {
360         SpaceIpo *sipo= CTX_wm_space_graph(C);
361
362         if(sipo->mode != SIPO_MODE_DRIVERS)
363                 return 0;
364
365         return graph_panel_context(C, NULL, NULL);
366 }
367
368
369 /* settings for 'single property' driver variable type */
370 static void graph_panel_driverVar__singleProp(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
371 {
372         DriverTarget *dtar= &dvar->targets[0];
373         PointerRNA dtar_ptr;
374         uiLayout *row, *col;
375         uiBlock *block;
376         
377         /* initialise RNA pointer to the target */
378         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
379         
380         /* Target ID */
381         row= uiLayoutRow(layout, 0);
382                 uiTemplateAnyID(row, (bContext *)C, &dtar_ptr, "id", "id_type", "Prop:");
383         
384         /* Target Property */
385         // TODO: make this less technical...
386         if (dtar->id) {
387                 PointerRNA root_ptr;
388                 
389                 /* get pointer for resolving the property selected */
390                 RNA_id_pointer_create(dtar->id, &root_ptr);
391                 
392                 col= uiLayoutColumn(layout, 1);
393                 block= uiLayoutGetBlock(col);
394                         /* rna path */
395                         uiTemplatePathBuilder(col, (bContext *)C, &dtar_ptr, "data_path", &root_ptr, "Path");
396         }
397 }
398
399 /* settings for 'rotation difference' driver variable type */
400 static void graph_panel_driverVar__rotDiff(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
401 {
402         DriverTarget *dtar= &dvar->targets[0];
403         DriverTarget *dtar2= &dvar->targets[1];
404         Object *ob1 = (Object *)dtar->id;
405         Object *ob2 = (Object *)dtar2->id;
406         PointerRNA dtar_ptr, dtar2_ptr;
407         uiLayout *col;
408         
409         /* initialise RNA pointer to the target */
410         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
411         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
412         
413         /* Bone 1 */
414         col= uiLayoutColumn(layout, 1);
415                 uiTemplateAnyID(col, (bContext *)C, &dtar_ptr, "id", "id_type", "Bone 1:");
416                 
417                 if (dtar->id && ob1->pose) {
418                         PointerRNA tar_ptr;
419                         
420                         RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
421                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
422                 }
423         
424         col= uiLayoutColumn(layout, 1);
425                 uiTemplateAnyID(col, (bContext *)C, &dtar2_ptr, "id", "id_type", "Bone 2:");
426                 
427                 if (dtar2->id && ob2->pose) {
428                         PointerRNA tar_ptr;
429                         
430                         RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
431                         uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
432                 }
433 }
434
435 /* settings for 'location difference' driver variable type */
436 static void graph_panel_driverVar__locDiff(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
437 {
438         DriverTarget *dtar= &dvar->targets[0];
439         DriverTarget *dtar2= &dvar->targets[1];
440         Object *ob1 = (Object *)dtar->id;
441         Object *ob2 = (Object *)dtar2->id;
442         PointerRNA dtar_ptr, dtar2_ptr;
443         uiLayout *col;
444         
445         /* initialise RNA pointer to the target */
446         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
447         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
448         
449         /* Bone 1 */
450         col= uiLayoutColumn(layout, 1);
451                 uiTemplateAnyID(col, (bContext *)C, &dtar_ptr, "id", "id_type", "Ob/Bone 1:");
452                 
453                 if (dtar->id && ob1->pose) {
454                         PointerRNA tar_ptr;
455                         
456                         RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
457                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
458                 }
459                 
460                 uiItemR(col, &dtar_ptr, "use_local_space_transform", 0, NULL, 0);
461         
462         col= uiLayoutColumn(layout, 1);
463                 uiTemplateAnyID(col, (bContext *)C, &dtar2_ptr, "id", "id_type", "Ob/Bone 2:");
464                 
465                 if (dtar2->id && ob2->pose) {
466                         PointerRNA tar_ptr;
467                         
468                         RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
469                         uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
470                 }
471                 
472                 uiItemR(col, &dtar2_ptr, "use_local_space_transform", 0, NULL, 0);
473 }
474
475 /* settings for 'transform channel' driver variable type */
476 static void graph_panel_driverVar__transChan(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
477 {
478         DriverTarget *dtar= &dvar->targets[0];
479         Object *ob = (Object *)dtar->id;
480         PointerRNA dtar_ptr;
481         uiLayout *col, *row;
482         
483         /* initialise RNA pointer to the target */
484         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
485         
486         /* properties */
487         col= uiLayoutColumn(layout, 1);
488                 uiTemplateAnyID(col, (bContext *)C, &dtar_ptr, "id", "id_type", "Ob/Bone:");
489                 
490                 if (dtar->id && ob->pose) {
491                         PointerRNA tar_ptr;
492                         
493                         RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
494                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
495                 }
496                 
497                 row= uiLayoutRow(layout, 1);
498                         uiItemR(row, &dtar_ptr, "transform_type", 0, "", 0);
499                         uiItemR(row, &dtar_ptr, "use_local_space_transform", 0, NULL, 0);
500 }
501
502 /* driver settings for active F-Curve (only for 'Drivers' mode) */
503 static void graph_panel_drivers(const bContext *C, Panel *pa)
504 {
505         bAnimListElem *ale;
506         FCurve *fcu;
507         ChannelDriver *driver;
508         DriverVar *dvar;
509         
510         PointerRNA driver_ptr;
511         uiLayout *col;
512         uiBlock *block;
513         uiBut *but;
514         
515         /* Get settings from context */
516         if (!graph_panel_context(C, &ale, &fcu))
517                 return;
518         driver= fcu->driver;
519         
520         /* set event handler for panel */
521         block= uiLayoutGetBlock(pa->layout); // xxx?
522         uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL);
523         
524         /* general actions - management */
525         col= uiLayoutColumn(pa->layout, 0);
526         block= uiLayoutGetBlock(col);
527                 but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Update Dependencies", 0, 0, 10*UI_UNIT_X, 22, NULL, 0.0, 0.0, 0, 0, "Force updates of dependencies");
528                 uiButSetFunc(but, driver_update_flags_cb, fcu, NULL);
529                 
530                 but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Remove Driver", 0, 0, 10*UI_UNIT_X, 18, NULL, 0.0, 0.0, 0, 0, "Remove this driver");
531                 uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
532                 
533         /* driver-level settings - type, expressions, and errors */
534         RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
535         
536         col= uiLayoutColumn(pa->layout, 1);
537         block= uiLayoutGetBlock(col);
538                 uiItemR(col, &driver_ptr, "type", 0, NULL, 0);
539                 
540                 /* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */
541                 if (driver->type == DRIVER_TYPE_PYTHON) {
542                         /* expression */
543                         uiItemR(col, &driver_ptr, "expression", 0, "Expr", 0);
544                         
545                         /* errors? */
546                         if (driver->flag & DRIVER_FLAG_INVALID)
547                                 uiItemL(col, "ERROR: invalid Python expression", ICON_ERROR);
548                 }
549                 else {
550                         /* errors? */
551                         if (driver->flag & DRIVER_FLAG_INVALID)
552                                 uiItemL(col, "ERROR: invalid target channel(s)", ICON_ERROR);
553                 }
554                 
555         col= uiLayoutColumn(pa->layout, 1);
556                 /* debug setting */
557                 uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, 0);
558                 
559                 /* value of driver */
560                 if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
561                         uiLayout *row= uiLayoutRow(col, 1);
562                         char valBuf[32];
563                         
564                         uiItemL(row, "Driver Value:", 0);
565                         
566                         sprintf(valBuf, "%.3f", driver->curval);
567                         uiItemL(row, valBuf, 0);
568                 }
569         
570         /* add driver variables */
571         col= uiLayoutColumn(pa->layout, 0);
572         block= uiLayoutGetBlock(col);
573                 but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Add Variable", 0, 0, 10*UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "Add a new target variable for this Driver");
574                 uiButSetFunc(but, driver_add_var_cb, driver, NULL);
575         
576         /* loop over targets, drawing them */
577         for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
578                 PointerRNA dvar_ptr;
579                 uiLayout *box, *row;
580                 
581                 /* sub-layout column for this variable's settings */
582                 col= uiLayoutColumn(pa->layout, 1);
583                 
584                 /* header panel */
585                 box= uiLayoutBox(col);
586                         /* first row context info for driver */
587                         RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
588                         
589                         row= uiLayoutRow(box, 0);
590                         block= uiLayoutGetBlock(row);
591                                 /* variable name */
592                                 uiItemR(row, &dvar_ptr, "name", 0, "", 0);
593                                 
594                                 /* remove button */
595                                 uiBlockSetEmboss(block, UI_EMBOSSN);
596                                         but= uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete target variable.");
597                                         uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
598                                 uiBlockSetEmboss(block, UI_EMBOSS);
599                         
600                         /* variable type */
601                         row= uiLayoutRow(box, 0);
602                                 uiItemR(row, &dvar_ptr, "type", 0, "", 0);
603                                 
604                 /* variable type settings */
605                 box= uiLayoutBox(col);
606                         /* controls to draw depends on the type of variable */
607                         switch (dvar->type) {
608                                 case DVAR_TYPE_SINGLE_PROP:     /* single property */
609                                         graph_panel_driverVar__singleProp(C, box, ale->id, dvar);
610                                         break;
611                                 case DVAR_TYPE_ROT_DIFF: /* rotational difference */
612                                         graph_panel_driverVar__rotDiff(C, box, ale->id, dvar);
613                                         break;
614                                 case DVAR_TYPE_LOC_DIFF: /* location difference */
615                                         graph_panel_driverVar__locDiff(C, box, ale->id, dvar);
616                                         break;
617                                 case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
618                                         graph_panel_driverVar__transChan(C, box, ale->id, dvar);
619                                         break;
620                         }
621                         
622                 /* value of variable */
623                 if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
624                         uiLayout *row;
625                         char valBuf[32];
626                         
627                         box= uiLayoutBox(col);
628                         row= uiLayoutRow(box, 1);
629                                 uiItemL(row, "Value:", 0);
630                                 
631                                 sprintf(valBuf, "%.3f", dvar->curval);
632                                 uiItemL(row, valBuf, 0);
633                 }
634         }
635         
636         /* cleanup */
637         MEM_freeN(ale);
638 }
639
640 /* ******************* f-modifiers ******************************** */
641 /* all the drawing code is in editors/animation/fmodifier_ui.c */
642
643 #define B_FMODIFIER_REDRAW              20
644
645 static void do_graph_region_modifier_buttons(bContext *C, void *arg, int event)
646 {
647         switch (event) {
648                 case B_REDR:
649                 case B_FMODIFIER_REDRAW: // XXX this should send depsgraph updates too
650                         WM_event_add_notifier(C, NC_ANIMATION, NULL); // XXX need a notifier specially for F-Modifiers
651                         break;
652         }
653 }
654
655 static void graph_panel_modifiers(const bContext *C, Panel *pa) 
656 {
657         bAnimListElem *ale;
658         FCurve *fcu;
659         FModifier *fcm;
660         uiLayout *col, *row;
661         uiBlock *block;
662         
663         if (!graph_panel_context(C, &ale, &fcu))
664                 return;
665         
666         block= uiLayoutGetBlock(pa->layout);
667         uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
668         
669         /* 'add modifier' button at top of panel */
670         {
671                 row= uiLayoutRow(pa->layout, 0);
672                 block= uiLayoutGetBlock(row);
673                 
674                 // XXX for now, this will be a operator button which calls a 'add modifier' operator
675                 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");
676                 
677                 /* copy/paste (as sub-row)*/
678                 row= uiLayoutRow(row, 1);
679                         uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
680                         uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
681         }
682         
683         /* draw each modifier */
684         for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
685                 col= uiLayoutColumn(pa->layout, 1);
686                 
687                 ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
688         }
689
690         MEM_freeN(ale);
691 }
692
693 /* ******************* general ******************************** */
694
695 void graph_buttons_register(ARegionType *art)
696 {
697         PanelType *pt;
698
699         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
700         strcpy(pt->idname, "GRAPH_PT_view");
701         strcpy(pt->label, "View Properties");
702         pt->draw= graph_panel_view;
703         pt->flag |= PNL_DEFAULT_CLOSED;
704         BLI_addtail(&art->paneltypes, pt);
705         
706         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
707         strcpy(pt->idname, "GRAPH_PT_properties");
708         strcpy(pt->label, "Active F-Curve");
709         pt->draw= graph_panel_properties;
710         pt->poll= graph_panel_poll;
711         BLI_addtail(&art->paneltypes, pt);
712         
713         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
714         strcpy(pt->idname, "GRAPH_PT_key_properties");
715         strcpy(pt->label, "Active Keyframe");
716         pt->draw= graph_panel_key_properties;
717         pt->poll= graph_panel_poll;
718         BLI_addtail(&art->paneltypes, pt);
719
720
721         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
722         strcpy(pt->idname, "GRAPH_PT_drivers");
723         strcpy(pt->label, "Drivers");
724         pt->draw= graph_panel_drivers;
725         pt->poll= graph_panel_drivers_poll;
726         BLI_addtail(&art->paneltypes, pt);
727
728         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
729         strcpy(pt->idname, "GRAPH_PT_modifiers");
730         strcpy(pt->label, "Modifiers");
731         pt->draw= graph_panel_modifiers;
732         pt->poll= graph_panel_poll;
733         BLI_addtail(&art->paneltypes, pt);
734 }
735
736 static int graph_properties(bContext *C, wmOperator *UNUSED(op))
737 {
738         ScrArea *sa= CTX_wm_area(C);
739         ARegion *ar= graph_has_buttons_region(sa);
740         
741         if(ar)
742                 ED_region_toggle_hidden(C, ar);
743
744         return OPERATOR_FINISHED;
745 }
746
747 void GRAPH_OT_properties(wmOperatorType *ot)
748 {
749         ot->name= "Properties";
750         ot->idname= "GRAPH_OT_properties";
751         
752         ot->exec= graph_properties;
753         ot->poll= ED_operator_ipo_active; // xxx
754         
755         /* flags */
756         ot->flag= 0;
757 }