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