Invalid Driver Targets are now indicated appropriately (using Red Backgrounds)
[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 /* ******************* graph editor space & buttons ************** */
73
74 #define B_REDR 1
75
76 /* -------------- */
77
78 static void do_graph_region_buttons(bContext *UNUSED(C), void *UNUSED(arg), int event)
79 {
80         //Scene *scene = CTX_data_scene(C);
81         
82         switch (event) {
83
84         }
85         
86         /* default for now */
87         //WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
88 }
89
90 /* -------------- */
91
92 static int graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
93 {
94         bAnimContext ac;
95         bAnimListElem *elem = NULL;
96         
97         /* for now, only draw if we could init the anim-context info (necessary for all animation-related tools) 
98          * to work correctly is able to be correctly retrieved. There's no point showing empty panels?
99          */
100         if (ANIM_animdata_get_context(C, &ac) == 0) 
101                 return 0;
102         
103         /* try to find 'active' F-Curve */
104         elem = get_active_fcurve_channel(&ac);
105         if (elem == NULL) 
106                 return 0;
107         
108         if (fcu)
109                 *fcu = (FCurve *)elem->data;
110         if (ale)
111                 *ale = elem;
112         else
113                 MEM_freeN(elem);
114         
115         return 1;
116 }
117
118 static int graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
119 {
120         return graph_panel_context(C, NULL, NULL);
121 }
122
123 /* -------------- */
124
125 /* Graph Editor View Settings */
126 static void graph_panel_view(const bContext *C, Panel *pa)
127 {
128         bScreen *sc = CTX_wm_screen(C);
129         SpaceIpo *sipo = CTX_wm_space_graph(C);
130         Scene *scene = CTX_data_scene(C);
131         PointerRNA spaceptr, sceneptr;
132         uiLayout *col, *sub, *row;
133         
134         /* get RNA pointers for use when creating the UI elements */
135         RNA_id_pointer_create(&scene->id, &sceneptr);
136         RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
137
138         /* 2D-Cursor */
139         col = uiLayoutColumn(pa->layout, FALSE);
140         uiItemR(col, &spaceptr, "show_cursor", 0, NULL, ICON_NONE);
141                 
142         sub = uiLayoutColumn(col, TRUE);
143         uiLayoutSetActive(sub, RNA_boolean_get(&spaceptr, "show_cursor"));
144         uiItemO(sub, IFACE_("Cursor from Selection"), ICON_NONE, "GRAPH_OT_frame_jump");
145
146         sub = uiLayoutColumn(col, TRUE);
147         uiLayoutSetActive(sub, RNA_boolean_get(&spaceptr, "show_cursor"));
148         row = uiLayoutSplit(sub, 0.7f, TRUE);
149         uiItemR(row, &sceneptr, "frame_current", 0, IFACE_("Cursor X"), ICON_NONE);
150         uiItemEnumO(row, "GRAPH_OT_snap", IFACE_("To Keys"), 0, "type", GRAPHKEYS_SNAP_CFRA);
151         
152         row = uiLayoutSplit(sub, 0.7f, TRUE);
153         uiItemR(row, &spaceptr, "cursor_position_y", 0, IFACE_("Cursor Y"), ICON_NONE);
154         uiItemEnumO(row, "GRAPH_OT_snap", IFACE_("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, *sub;
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, FALSE);
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, TRUE);
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, ICON_NONE);
190                 
191         /* color settings */
192         col = uiLayoutColumn(layout, TRUE);
193         uiItemL(col, IFACE_("Display Color:"), ICON_NONE);
194                 
195         row = uiLayoutRow(col, TRUE);
196         uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE);
197                         
198         sub = uiLayoutRow(row, TRUE);
199         uiLayoutSetEnabled(sub, (fcu->color_mode == FCURVE_COLOR_CUSTOM));
200         uiItemR(sub, &fcu_ptr, "color", 0, "", ICON_NONE);
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 /* update callback for active keyframe properties - base updates stuff */
242 static void graphedit_activekey_update_cb(bContext *C, void *fcu_ptr, void *UNUSED(bezt_ptr))
243 {
244         SpaceIpo *sipo = CTX_wm_space_graph(C);
245         const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
246         FCurve *fcu = (FCurve *)fcu_ptr;
247         
248         /* make sure F-Curve and its handles are still valid after this editing */
249         sort_time_fcurve(fcu);
250         testhandles_fcurve(fcu, use_handle);
251 }
252
253 /* update callback for active keyframe properties - handle-editing wrapper */
254 static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
255 {
256         BezTriple *bezt = (BezTriple *)bezt_ptr;
257         
258         /* since editing the handles, make sure they're set to types which are receptive to editing 
259          * see transform_conversions.c :: createTransGraphEditData(), last step in second loop
260          */
261         if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
262                 /* by changing to aligned handles, these can now be moved... */
263                 bezt->h1 = HD_ALIGN;
264                 bezt->h2 = HD_ALIGN;
265         }
266         
267         /* now call standard updates */
268         graphedit_activekey_update_cb(C, fcu_ptr, bezt_ptr);
269 }
270
271 static void graph_panel_key_properties(const bContext *C, Panel *pa)
272 {
273         bAnimListElem *ale;
274         FCurve *fcu;
275         BezTriple *bezt, *prevbezt;
276         
277         uiLayout *layout = pa->layout;
278         uiLayout *col;
279         uiBlock *block;
280
281         if (!graph_panel_context(C, &ale, &fcu))
282                 return;
283         
284         block = uiLayoutGetBlock(layout);
285         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
286         
287         /* only show this info if there are keyframes to edit */
288         if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
289                 PointerRNA bezt_ptr, id_ptr, fcu_prop_ptr;
290                 PropertyRNA *fcu_prop = NULL;
291                 uiBut *but;
292                 int unit = B_UNIT_NONE;
293                 
294                 /* RNA pointer to keyframe, to allow editing */
295                 RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr);
296                 
297                 /* get property that F-Curve affects, for some unit-conversion magic */
298                 RNA_id_pointer_create(ale->id, &id_ptr);
299                 if (RNA_path_resolve(&id_ptr, fcu->rna_path, &fcu_prop_ptr, &fcu_prop) && fcu_prop) {
300                         /* determine the unit for this property */
301                         unit = RNA_SUBTYPE_UNIT(RNA_property_subtype(fcu_prop));
302                 }
303                 
304                 /* interpolation */
305                 col = uiLayoutColumn(layout, FALSE);
306                 uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
307                         
308                 /* numerical coordinate editing 
309                  *  - we use the button-versions of the calls so that we can attach special update handlers
310                  *    and unit conversion magic that cannot be achieved using a purely RNA-approach
311                  */
312                 col = uiLayoutColumn(layout, TRUE);
313                 /* keyframe itself */
314                 {
315                         uiItemL(col, IFACE_("Key:"), ICON_NONE);
316                         
317                         but = uiDefButR(block, NUM, B_REDR, IFACE_("Frame"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
318                                         &bezt_ptr, "co", 0, 0, 0, -1, -1, NULL);
319                         uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
320                         
321                         but = uiDefButR(block, NUM, B_REDR, IFACE_("Value"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
322                                         &bezt_ptr, "co", 1, 0, 0, -1, -1, NULL);
323                         uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt);
324                         uiButSetUnitType(but, unit);
325                 }
326                 
327                 /* previous handle - only if previous was Bezier interpolation */
328                 if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
329                         uiItemL(col, IFACE_("Left Handle:"), ICON_NONE);
330                         
331                         but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y,
332                                         &bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL);
333                         uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
334                         
335                         but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y,
336                                         &bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL);
337                         uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
338                         uiButSetUnitType(but, unit);
339                 }
340                 
341                 /* next handle - only if current is Bezier interpolation */
342                 if (bezt->ipo == BEZT_IPO_BEZ) {
343                         uiItemL(col, IFACE_("Right Handle:"), ICON_NONE);
344                         
345                         but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y,
346                                         &bezt_ptr, "handle_right", 0, 0, 0, -1, -1, NULL);
347                         uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
348                         
349                         but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y,
350                                         &bezt_ptr, "handle_right", 1, 0, 0, -1, -1, NULL);
351                         uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
352                         uiButSetUnitType(but, unit);
353                 }
354         }
355         else {
356                 if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
357                         /* modifiers only - so no keyframes to be active */
358                         uiItemL(layout, IFACE_("F-Curve only has F-Modifiers"), ICON_NONE);
359                         uiItemL(layout, IFACE_("See Modifiers panel below"), ICON_INFO);
360                 }
361                 else if (fcu->fpt) {
362                         /* samples only */
363                         uiItemL(layout, IFACE_("F-Curve doesn't have any keyframes as it only contains sampled points"),
364                                 ICON_NONE);
365                 }
366                 else
367                         uiItemL(layout, IFACE_("No active keyframe on F-Curve"), ICON_NONE);
368         }
369         
370         MEM_freeN(ale);
371 }
372
373 /* ******************* drivers ******************************** */
374
375 #define B_IPO_DEPCHANGE     10
376
377 static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int event)
378 {
379         Main *bmain = CTX_data_main(C);
380         Scene *scene = CTX_data_scene(C);
381         
382         switch (event) {
383                 case B_IPO_DEPCHANGE:
384                 {
385                         /* rebuild depsgraph for the new deps */
386                         DAG_relations_tag_update(bmain);
387                 }
388                 break;
389         }
390         
391         /* default for now */
392         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene); // XXX could use better notifier
393 }
394
395 /* callback to remove the active driver */
396 static void driver_remove_cb(bContext *C, void *ale_v, void *UNUSED(arg))
397 {
398         bAnimListElem *ale = (bAnimListElem *)ale_v;
399         ID *id = ale->id;
400         FCurve *fcu = ale->data;
401         ReportList *reports = CTX_wm_reports(C);
402         
403         /* try to get F-Curve that driver lives on, and ID block which has this AnimData */
404         if (ELEM(NULL, id, fcu))
405                 return;
406         
407         /* call API method to remove this driver  */
408         ANIM_remove_driver(reports, id, fcu->rna_path, fcu->array_index, 0);
409 }
410
411 /* callback to add a target variable to the active driver */
412 static void driver_add_var_cb(bContext *UNUSED(C), void *driver_v, void *UNUSED(arg))
413 {
414         ChannelDriver *driver = (ChannelDriver *)driver_v;
415         
416         /* add a new variable */
417         driver_add_new_variable(driver);
418 }
419
420 /* callback to remove target variable from active driver */
421 static void driver_delete_var_cb(bContext *UNUSED(C), void *driver_v, void *dvar_v)
422 {
423         ChannelDriver *driver = (ChannelDriver *)driver_v;
424         DriverVar *dvar = (DriverVar *)dvar_v;
425         
426         /* remove the active variable */
427         driver_free_variable(driver, dvar);
428 }
429
430 /* callback to reset the driver's flags */
431 static void driver_update_flags_cb(bContext *UNUSED(C), void *fcu_v, void *UNUSED(arg))
432 {
433         FCurve *fcu = (FCurve *)fcu_v;
434         ChannelDriver *driver = fcu->driver;
435         
436         /* clear invalid flags */
437         fcu->flag &= ~FCURVE_DISABLED;
438         driver->flag &= ~DRIVER_FLAG_INVALID;
439 }
440
441 /* drivers panel poll */
442 static int graph_panel_drivers_poll(const bContext *C, PanelType *UNUSED(pt))
443 {
444         SpaceIpo *sipo = CTX_wm_space_graph(C);
445
446         if (sipo->mode != SIPO_MODE_DRIVERS)
447                 return 0;
448
449         return graph_panel_context(C, NULL, NULL);
450 }
451
452 /* settings for 'single property' driver variable type */
453 static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVar *dvar)
454 {
455         DriverTarget *dtar = &dvar->targets[0];
456         PointerRNA dtar_ptr;
457         uiLayout *row, *col;
458         
459         /* initialize RNA pointer to the target */
460         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
461         
462         /* Target ID */
463         row = uiLayoutRow(layout, FALSE);
464         uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
465         uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
466         
467         /* Target Property */
468         if (dtar->id) {
469                 PointerRNA root_ptr;
470                 
471                 /* get pointer for resolving the property selected */
472                 RNA_id_pointer_create(dtar->id, &root_ptr);
473                 
474                 /* rna path */
475                 col = uiLayoutColumn(layout, TRUE);
476                 uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID));
477                 uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
478         }
479 }
480
481 /* settings for 'rotation difference' driver variable type */
482 static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
483 {
484         DriverTarget *dtar = &dvar->targets[0];
485         DriverTarget *dtar2 = &dvar->targets[1];
486         Object *ob1 = (Object *)dtar->id;
487         Object *ob2 = (Object *)dtar2->id;
488         PointerRNA dtar_ptr, dtar2_ptr;
489         uiLayout *col;
490         
491         /* initialize RNA pointer to the target */
492         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
493         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
494         
495         /* Bone 1 */
496         col = uiLayoutColumn(layout, TRUE);
497         uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
498         uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
499         
500         if (dtar->id && ob1->pose) {
501                 PointerRNA tar_ptr;
502                 
503                 RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
504                 uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
505         }
506         
507         col = uiLayoutColumn(layout, TRUE);
508         uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
509         uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
510                 
511         if (dtar2->id && ob2->pose) {
512                 PointerRNA tar_ptr;
513                 
514                 RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
515                 uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
516         }
517 }
518
519 /* settings for 'location difference' driver variable type */
520 static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
521 {
522         DriverTarget *dtar  = &dvar->targets[0];
523         DriverTarget *dtar2 = &dvar->targets[1];
524         Object *ob1 = (Object *)dtar->id;
525         Object *ob2 = (Object *)dtar2->id;
526         PointerRNA dtar_ptr, dtar2_ptr;
527         uiLayout *col;
528         
529         /* initialize RNA pointer to the target */
530         RNA_pointer_create(id, &RNA_DriverTarget, dtar,  &dtar_ptr); 
531         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
532         
533         /* Bone 1 */
534         col = uiLayoutColumn(layout, TRUE);
535         uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
536         uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
537                 
538         if (dtar->id && ob1->pose) {
539                 PointerRNA tar_ptr;
540                 
541                 RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
542                 uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
543         }
544                 
545         uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
546         
547         col = uiLayoutColumn(layout, TRUE);
548         uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
549         uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
550                 
551         if (dtar2->id && ob2->pose) {
552                 PointerRNA tar_ptr;
553                 
554                 RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
555                 uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
556         }
557                 
558         uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE);
559 }
560
561 /* settings for 'transform channel' driver variable type */
562 static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar *dvar)
563 {
564         DriverTarget *dtar = &dvar->targets[0];
565         Object *ob = (Object *)dtar->id;
566         PointerRNA dtar_ptr;
567         uiLayout *col, *sub;
568         
569         /* initialize RNA pointer to the target */
570         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
571         
572         /* properties */
573         col = uiLayoutColumn(layout, TRUE);
574         uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
575         uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
576                 
577         if (dtar->id && ob->pose) {
578                 PointerRNA tar_ptr;
579                 
580                 RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
581                 uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
582         }
583                 
584         sub = uiLayoutColumn(layout, TRUE);
585         uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
586         uiItemR(sub, &dtar_ptr, "transform_space", 0, IFACE_("Space"), ICON_NONE);
587 }
588
589 /* driver settings for active F-Curve (only for 'Drivers' mode) */
590 static void graph_panel_drivers(const bContext *C, Panel *pa)
591 {
592         bAnimListElem *ale;
593         FCurve *fcu;
594         ChannelDriver *driver;
595         DriverVar *dvar;
596         
597         PointerRNA driver_ptr;
598         uiLayout *col;
599         uiBlock *block;
600         uiBut *but;
601         
602         /* Get settings from context */
603         if (!graph_panel_context(C, &ale, &fcu))
604                 return;
605         driver = fcu->driver;
606         
607         /* set event handler for panel */
608         block = uiLayoutGetBlock(pa->layout); // xxx?
609         uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL);
610         
611         /* general actions - management */
612         col = uiLayoutColumn(pa->layout, FALSE);
613         block = uiLayoutGetBlock(col);
614         but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Update Dependencies"), 0, 0, 10 * UI_UNIT_X, 22,
615                        NULL, 0.0, 0.0, 0, 0, TIP_("Force updates of dependencies"));
616         uiButSetFunc(but, driver_update_flags_cb, fcu, NULL);
617
618         but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Remove Driver"), 0, 0, 10 * UI_UNIT_X, 18,
619                        NULL, 0.0, 0.0, 0, 0, TIP_("Remove this driver"));
620         uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
621                 
622         /* driver-level settings - type, expressions, and errors */
623         RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
624         
625         col = uiLayoutColumn(pa->layout, TRUE);
626         block = uiLayoutGetBlock(col);
627         uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);
628
629         /* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */
630         if (driver->type == DRIVER_TYPE_PYTHON) {
631                 /* expression */
632                 uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
633                 
634                 /* errors? */
635                 if (driver->flag & DRIVER_FLAG_INVALID)
636                         uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_ERROR);
637         }
638         else {
639                 /* errors? */
640                 if (driver->flag & DRIVER_FLAG_INVALID)
641                         uiItemL(col, IFACE_("ERROR: Invalid target channel(s)"), ICON_ERROR);
642         }
643                 
644         col = uiLayoutColumn(pa->layout, TRUE);
645         /* debug setting */
646         uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE);
647                 
648         /* value of driver */
649         if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
650                 uiLayout *row = uiLayoutRow(col, TRUE);
651                 char valBuf[32];
652                         
653                 uiItemL(row, IFACE_("Driver Value:"), ICON_NONE);
654                         
655                 BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval);
656                 uiItemL(row, valBuf, ICON_NONE);
657         }
658         
659         /* add driver variables */
660         col = uiLayoutColumn(pa->layout, FALSE);
661         block = uiLayoutGetBlock(col);
662         but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Add Variable"), 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
663                        NULL, 0.0, 0.0, 0, 0, TIP_("Add a new target variable for this Driver"));
664         uiButSetFunc(but, driver_add_var_cb, driver, NULL);
665         
666         /* loop over targets, drawing them */
667         for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
668                 PointerRNA dvar_ptr;
669                 uiLayout *box, *row;
670                 
671                 /* sub-layout column for this variable's settings */
672                 col = uiLayoutColumn(pa->layout, TRUE);
673                 
674                 /* header panel */
675                 box = uiLayoutBox(col);
676                 /* first row context info for driver */
677                 RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
678                 
679                 row = uiLayoutRow(box, FALSE);
680                 block = uiLayoutGetBlock(row);
681                 /* variable name */
682                 uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
683                 
684                 /* remove button */
685                 uiBlockSetEmboss(block, UI_EMBOSSN);
686                 but = uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
687                                    NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
688                 uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
689                 uiBlockSetEmboss(block, UI_EMBOSS);
690                 
691                 /* variable type */
692                 row = uiLayoutRow(box, FALSE);
693                 uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
694                                 
695                 /* variable type settings */
696                 box = uiLayoutBox(col);
697                 /* controls to draw depends on the type of variable */
698                 switch (dvar->type) {
699                         case DVAR_TYPE_SINGLE_PROP:     /* single property */
700                                 graph_panel_driverVar__singleProp(box, ale->id, dvar);
701                                 break;
702                         case DVAR_TYPE_ROT_DIFF:     /* rotational difference */
703                                 graph_panel_driverVar__rotDiff(box, ale->id, dvar);
704                                 break;
705                         case DVAR_TYPE_LOC_DIFF:     /* location difference */
706                                 graph_panel_driverVar__locDiff(box, ale->id, dvar);
707                                 break;
708                         case DVAR_TYPE_TRANSFORM_CHAN:     /* transform channel */
709                                 graph_panel_driverVar__transChan(box, ale->id, dvar);
710                                 break;
711                 }
712                 
713                 /* value of variable */
714                 if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
715                         char valBuf[32];
716                         
717                         box = uiLayoutBox(col);
718                         row = uiLayoutRow(box, TRUE);
719                         uiItemL(row, IFACE_("Value:"), ICON_NONE);
720                         
721                         if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
722                             (dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
723                              dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
724                              dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX))
725                         {
726                                 BLI_snprintf(valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
727                         }
728                         else {
729                                 BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
730                         }
731                         
732                         uiItemL(row, valBuf, ICON_NONE);
733                 }
734         }
735         
736         /* cleanup */
737         MEM_freeN(ale);
738 }
739
740 /* ******************* F-Modifiers ******************************** */
741 /* All the drawing code is in editors/animation/fmodifier_ui.c */
742
743 #define B_FMODIFIER_REDRAW      20
744
745 static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
746 {
747         switch (event) {
748                 case B_FMODIFIER_REDRAW: // XXX this should send depsgraph updates too
749                         WM_event_add_notifier(C, NC_ANIMATION, NULL); // XXX need a notifier specially for F-Modifiers
750                         break;
751         }
752 }
753
754 static void graph_panel_modifiers(const bContext *C, Panel *pa) 
755 {
756         bAnimListElem *ale;
757         FCurve *fcu;
758         FModifier *fcm;
759         uiLayout *col, *row;
760         uiBlock *block;
761         
762         if (!graph_panel_context(C, &ale, &fcu))
763                 return;
764         
765         block = uiLayoutGetBlock(pa->layout);
766         uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
767         
768         /* 'add modifier' button at top of panel */
769         {
770                 row = uiLayoutRow(pa->layout, FALSE);
771                 block = uiLayoutGetBlock(row);
772                 
773                 /* this is an operator button which calls a 'add modifier' operator... 
774                  * a menu might be nicer but would be tricky as we need some custom filtering
775                  */
776                 uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"),
777                           10, 0, 150, 20, TIP_("Adds a new F-Curve Modifier for the active F-Curve"));
778                 
779                 /* copy/paste (as sub-row)*/
780                 row = uiLayoutRow(row, TRUE);
781                 uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
782                 uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
783         }
784         
785         /* draw each modifier */
786         for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
787                 col = uiLayoutColumn(pa->layout, TRUE);
788                 
789                 ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
790         }
791
792         MEM_freeN(ale);
793 }
794
795 /* ******************* general ******************************** */
796
797 void graph_buttons_register(ARegionType *art)
798 {
799         PanelType *pt;
800
801         pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
802         strcpy(pt->idname, "GRAPH_PT_view");
803         strcpy(pt->label, N_("View Properties"));
804         pt->draw = graph_panel_view;
805         pt->flag |= PNL_DEFAULT_CLOSED;
806         BLI_addtail(&art->paneltypes, pt);
807         
808         pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
809         strcpy(pt->idname, "GRAPH_PT_properties");
810         strcpy(pt->label, N_("Active F-Curve"));
811         pt->draw = graph_panel_properties;
812         pt->poll = graph_panel_poll;
813         BLI_addtail(&art->paneltypes, pt);
814         
815         pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
816         strcpy(pt->idname, "GRAPH_PT_key_properties");
817         strcpy(pt->label, N_("Active Keyframe"));
818         pt->draw = graph_panel_key_properties;
819         pt->poll = graph_panel_poll;
820         BLI_addtail(&art->paneltypes, pt);
821
822
823         pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
824         strcpy(pt->idname, "GRAPH_PT_drivers");
825         strcpy(pt->label, N_("Drivers"));
826         pt->draw = graph_panel_drivers;
827         pt->poll = graph_panel_drivers_poll;
828         BLI_addtail(&art->paneltypes, pt);
829
830         pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
831         strcpy(pt->idname, "GRAPH_PT_modifiers");
832         strcpy(pt->label, N_("Modifiers"));
833         pt->draw = graph_panel_modifiers;
834         pt->poll = graph_panel_poll;
835         BLI_addtail(&art->paneltypes, pt);
836 }
837
838 static int graph_properties(bContext *C, wmOperator *UNUSED(op))
839 {
840         ScrArea *sa = CTX_wm_area(C);
841         ARegion *ar = graph_has_buttons_region(sa);
842         
843         if (ar)
844                 ED_region_toggle_hidden(C, ar);
845
846         return OPERATOR_FINISHED;
847 }
848
849 void GRAPH_OT_properties(wmOperatorType *ot)
850 {
851         ot->name = "Properties";
852         ot->idname = "GRAPH_OT_properties";
853         ot->description = "Toggle display properties panel";
854         
855         ot->exec = graph_properties;
856         ot->poll = ED_operator_graphedit_active;
857
858         /* flags */
859         ot->flag = 0;
860 }