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