Blender  V2.59
graph_buttons.c
Go to the documentation of this file.
00001 /*
00002  * $Id: graph_buttons.c 36276 2011-04-21 15:53:30Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation, Joshua Leung
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <string.h>
00035 #include <stdio.h>
00036 #include <math.h>
00037 #include <float.h>
00038 
00039 #include "DNA_anim_types.h"
00040 #include "DNA_object_types.h"
00041 #include "DNA_scene_types.h"
00042 
00043 #include "MEM_guardedalloc.h"
00044 
00045 #include "BLI_math.h"
00046 #include "BLI_blenlib.h"
00047 #include "BLI_editVert.h"
00048 #include "BLI_rand.h"
00049 #include "BLI_utildefines.h"
00050 
00051 #include "BKE_context.h"
00052 #include "BKE_depsgraph.h"
00053 #include "BKE_fcurve.h"
00054 #include "BKE_main.h"
00055 #include "BKE_screen.h"
00056 
00057 
00058 #include "WM_api.h"
00059 #include "WM_types.h"
00060 
00061 #include "RNA_access.h"
00062 
00063 #include "ED_anim_api.h"
00064 #include "ED_keyframing.h"
00065 #include "ED_screen.h"
00066 
00067 #include "UI_interface.h"
00068 #include "UI_resources.h"
00069 
00070 #include "graph_intern.h"       // own include
00071 
00072 /* XXX */
00073 
00074 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
00075 #define UI_FLT_MAX      10000.0f
00076 
00077 
00078 /* ******************* graph editor space & buttons ************** */
00079 
00080 #define B_NOP           1
00081 #define B_REDR          2
00082 
00083 /* -------------- */
00084 
00085 static void do_graph_region_buttons(bContext *UNUSED(C), void *UNUSED(arg), int event)
00086 {
00087         //Scene *scene= CTX_data_scene(C);
00088         
00089         switch(event) {
00090 
00091         }
00092         
00093         /* default for now */
00094         //WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
00095 }
00096 
00097 /* -------------- */
00098 
00099 static int graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu)
00100 {
00101         bAnimContext ac;
00102         bAnimListElem *elem= NULL;
00103         
00104         /* for now, only draw if we could init the anim-context info (necessary for all animation-related tools) 
00105          * to work correctly is able to be correctly retrieved. There's no point showing empty panels?
00106          */
00107         if (ANIM_animdata_get_context(C, &ac) == 0) 
00108                 return 0;
00109         
00110         /* try to find 'active' F-Curve */
00111         elem= get_active_fcurve_channel(&ac);
00112         if(elem == NULL) 
00113                 return 0;
00114         
00115         if(fcu)
00116                 *fcu= (FCurve*)elem->data;
00117         if(ale)
00118                 *ale= elem;
00119         else
00120                 MEM_freeN(elem);
00121         
00122         return 1;
00123 }
00124 
00125 static int graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
00126 {
00127         return graph_panel_context(C, NULL, NULL);
00128 }
00129 
00130 /* -------------- */
00131 
00132 /* Graph Editor View Settings */
00133 static void graph_panel_view(const bContext *C, Panel *pa)
00134 {
00135         bScreen *sc= CTX_wm_screen(C);
00136         SpaceIpo *sipo= CTX_wm_space_graph(C);
00137         Scene *scene= CTX_data_scene(C);
00138         PointerRNA spaceptr, sceneptr;
00139         uiLayout *col, *subcol, *row;
00140         
00141         /* get RNA pointers for use when creating the UI elements */
00142         RNA_id_pointer_create(&scene->id, &sceneptr);
00143         RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
00144 
00145         /* 2D-Cursor */
00146         col= uiLayoutColumn(pa->layout, 0);
00147                 uiItemR(col, &spaceptr, "show_cursor", 0, NULL, ICON_NONE);
00148                 
00149                 subcol= uiLayoutColumn(col, 1);
00150                 uiLayoutSetActive(subcol, RNA_boolean_get(&spaceptr, "show_cursor")); 
00151                         uiItemO(subcol, "Cursor from Selection", ICON_NONE, "GRAPH_OT_frame_jump");
00152                 
00153                 subcol= uiLayoutColumn(col, 1);
00154                 uiLayoutSetActive(subcol, RNA_boolean_get(&spaceptr, "show_cursor")); 
00155                         row= uiLayoutSplit(subcol, 0.7, 1);
00156                                 uiItemR(row, &sceneptr, "frame_current", 0, "Cursor X", ICON_NONE);
00157                                 uiItemEnumO(row, "GRAPH_OT_snap", "To Keys", 0, "type", GRAPHKEYS_SNAP_CFRA);
00158                         row= uiLayoutSplit(subcol, 0.7, 1);
00159                                 uiItemR(row, &spaceptr, "cursor_position_y", 0, "Cursor Y", ICON_NONE);
00160                                 uiItemEnumO(row, "GRAPH_OT_snap", "To Keys", 0, "type", GRAPHKEYS_SNAP_VALUE);
00161 }
00162 
00163 /* ******************* active F-Curve ************** */
00164 
00165 static void graph_panel_properties(const bContext *C, Panel *pa)
00166 {
00167         bAnimListElem *ale;
00168         FCurve *fcu;
00169         PointerRNA fcu_ptr;
00170         uiLayout *layout = pa->layout;
00171         uiLayout *col, *row, *subrow;
00172         uiBlock *block;
00173         char name[256];
00174         int icon = 0;
00175 
00176         if (!graph_panel_context(C, &ale, &fcu))
00177                 return;
00178         
00179         block= uiLayoutGetBlock(layout);
00180         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
00181         
00182         /* F-Curve pointer */
00183         RNA_pointer_create(ale->id, &RNA_FCurve, fcu, &fcu_ptr);
00184         
00185         /* user-friendly 'name' for F-Curve */
00186         // TODO: only show the path if this is invalid?
00187         col= uiLayoutColumn(layout, 0);
00188                 icon= getname_anim_fcurve(name, ale->id, fcu);
00189                 uiItemL(col, name, icon);
00190                 
00191         /* RNA-Path Editing - only really should be enabled when things aren't working */
00192         col= uiLayoutColumn(layout, 1);
00193                 uiLayoutSetEnabled(col, (fcu->flag & FCURVE_DISABLED)!=0); 
00194                 uiItemR(col, &fcu_ptr, "data_path", 0, "", ICON_RNA);
00195                 uiItemR(col, &fcu_ptr, "array_index", 0, NULL, ICON_NONE);
00196                 
00197         /* color settings */
00198         col= uiLayoutColumn(layout, 1);
00199                 uiItemL(col, "Display Color:", ICON_NONE);
00200                 
00201                 row= uiLayoutRow(col, 1);
00202                         uiItemR(row, &fcu_ptr, "color_mode", 0, "", ICON_NONE);
00203                         
00204                         subrow= uiLayoutRow(row, 1);
00205                                 uiLayoutSetEnabled(subrow, (fcu->color_mode==FCURVE_COLOR_CUSTOM));
00206                                 uiItemR(subrow, &fcu_ptr, "color", 0, "", ICON_NONE);
00207         
00208         MEM_freeN(ale);
00209 }
00210 
00211 /* ******************* active Keyframe ************** */
00212 
00213 /* get 'active' keyframe for panel editing */
00214 static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezTriple **prevbezt)
00215 {
00216         BezTriple *b;
00217         int i;
00218         
00219         /* zero the pointers */
00220         *bezt = *prevbezt = NULL;
00221         
00222         /* sanity checks */
00223         if ((fcu->bezt == NULL) || (fcu->totvert == 0))
00224                 return 0;
00225                 
00226         /* find first selected keyframe for now, and call it the active one 
00227          *      - this is a reasonable assumption, given that whenever anyone 
00228          *        wants to edit numerically, there is likely to only be 1 vert selected
00229          */
00230         for (i=0, b=fcu->bezt; i < fcu->totvert; i++, b++) {
00231                 if (BEZSELECTED(b)) {
00232                         /* found 
00233                          *      - 'previous' is either the one before, of the keyframe itself (which is still fine)
00234                          *              XXX: we can just make this null instead if needed
00235                          */
00236                         *prevbezt = (i > 0) ? b-1 : b;
00237                         *bezt = b;
00238                         
00239                         return 1;
00240                 }
00241         }
00242         
00243         /* not found */
00244         return 0;
00245 }
00246 
00247 static void graph_panel_key_properties(const bContext *C, Panel *pa)
00248 {
00249         bAnimListElem *ale;
00250         FCurve *fcu;
00251         BezTriple *bezt, *prevbezt;
00252         
00253         uiLayout *layout = pa->layout;
00254         uiLayout *col;
00255         uiBlock *block;
00256 
00257         if (!graph_panel_context(C, &ale, &fcu))
00258                 return;
00259         
00260         block = uiLayoutGetBlock(layout);
00261         uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL);
00262         
00263         /* only show this info if there are keyframes to edit */
00264         if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) {
00265                 PointerRNA bezt_ptr;
00266                 
00267                 /* RNA pointer to keyframe, to allow editing */
00268                 RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr);
00269                 
00270                 /* interpolation */
00271                 col= uiLayoutColumn(layout, 0);
00272                         uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
00273                         
00274                 /* numerical coordinate editing */
00275                 col= uiLayoutColumn(layout, 1);
00276                         /* keyframe itself */
00277                         uiItemR(col, &bezt_ptr, "co", 0, "Key", ICON_NONE);
00278                         
00279                         /* previous handle - only if previous was Bezier interpolation */
00280                         if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ))
00281                                 uiItemR(col, &bezt_ptr, "handle_left", 0, NULL, ICON_NONE);
00282                         
00283                         /* next handle - only if current is Bezier interpolation */
00284                         if (bezt->ipo == BEZT_IPO_BEZ)
00285                                 uiItemR(col, &bezt_ptr, "handle_right", 0, NULL, ICON_NONE);
00286         }
00287         else {
00288                 if ((fcu->bezt == NULL) && (fcu->modifiers.first)) {
00289                         /* modifiers only - so no keyframes to be active */
00290                         uiItemL(layout, "F-Curve only has F-Modifiers", ICON_NONE);
00291                         uiItemL(layout, "See Modifiers panel below", ICON_INFO);
00292                 }
00293                 else if (fcu->fpt) {
00294                         /* samples only */
00295                         uiItemL(layout, "F-Curve doesn't have any keyframes as it only contains sampled points", ICON_NONE);
00296                 }
00297                 else
00298                         uiItemL(layout, "No active keyframe on F-Curve", ICON_NONE);
00299         }
00300         
00301         MEM_freeN(ale);
00302 }
00303 
00304 /* ******************* drivers ******************************** */
00305 
00306 #define B_IPO_DEPCHANGE         10
00307 
00308 static void do_graph_region_driver_buttons(bContext *C, void *UNUSED(arg), int event)
00309 {
00310         Main *bmain= CTX_data_main(C);
00311         Scene *scene= CTX_data_scene(C);
00312         
00313         switch (event) {
00314                 case B_IPO_DEPCHANGE:
00315                 {
00316                         /* rebuild depsgraph for the new deps */
00317                         DAG_scene_sort(bmain, scene);
00318                         
00319                         /* force an update of depsgraph */
00320                         DAG_ids_flush_update(bmain, 0);
00321                 }
00322                         break;
00323         }
00324         
00325         /* default for now */
00326         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene); // XXX could use better notifier
00327 }
00328 
00329 /* callback to remove the active driver */
00330 static void driver_remove_cb (bContext *C, void *ale_v, void *UNUSED(arg))
00331 {
00332         bAnimListElem *ale= (bAnimListElem *)ale_v;
00333         ID *id= ale->id;
00334         FCurve *fcu= ale->data;
00335         ReportList *reports = CTX_wm_reports(C);
00336         
00337         /* try to get F-Curve that driver lives on, and ID block which has this AnimData */
00338         if (ELEM(NULL, id, fcu))
00339                 return;
00340         
00341         /* call API method to remove this driver  */    
00342         ANIM_remove_driver(reports, id, fcu->rna_path, fcu->array_index, 0);
00343 }
00344 
00345 /* callback to add a target variable to the active driver */
00346 static void driver_add_var_cb (bContext *UNUSED(C), void *driver_v, void *UNUSED(arg))
00347 {
00348         ChannelDriver *driver= (ChannelDriver *)driver_v;
00349         
00350         /* add a new variable */
00351         driver_add_new_variable(driver);
00352 }
00353 
00354 /* callback to remove target variable from active driver */
00355 static void driver_delete_var_cb (bContext *UNUSED(C), void *driver_v, void *dvar_v)
00356 {
00357         ChannelDriver *driver= (ChannelDriver *)driver_v;
00358         DriverVar *dvar= (DriverVar *)dvar_v;
00359         
00360         /* remove the active variable */
00361         driver_free_variable(driver, dvar);
00362 }
00363 
00364 /* callback to reset the driver's flags */
00365 static void driver_update_flags_cb (bContext *UNUSED(C), void *fcu_v, void *UNUSED(arg))
00366 {
00367         FCurve *fcu= (FCurve *)fcu_v;
00368         ChannelDriver *driver= fcu->driver;
00369         
00370         /* clear invalid flags */
00371         fcu->flag &= ~FCURVE_DISABLED; // XXX?
00372         driver->flag &= ~DRIVER_FLAG_INVALID;
00373 }
00374 
00375 /* drivers panel poll */
00376 static int graph_panel_drivers_poll(const bContext *C, PanelType *UNUSED(pt))
00377 {
00378         SpaceIpo *sipo= CTX_wm_space_graph(C);
00379 
00380         if(sipo->mode != SIPO_MODE_DRIVERS)
00381                 return 0;
00382 
00383         return graph_panel_context(C, NULL, NULL);
00384 }
00385 
00386 /* settings for 'single property' driver variable type */
00387 static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVar *dvar)
00388 {
00389         DriverTarget *dtar= &dvar->targets[0];
00390         PointerRNA dtar_ptr;
00391         uiLayout *row, *col;
00392         
00393         /* initialise RNA pointer to the target */
00394         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
00395         
00396         /* Target ID */
00397         row= uiLayoutRow(layout, 0);
00398                 uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", "Prop:");
00399         
00400         /* Target Property */
00401         // TODO: make this less technical...
00402         if (dtar->id) {
00403                 PointerRNA root_ptr;
00404                 
00405                 /* get pointer for resolving the property selected */
00406                 RNA_id_pointer_create(dtar->id, &root_ptr);
00407                 
00408                 col= uiLayoutColumn(layout, 1);
00409                 /* rna path */
00410                 uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, "Path");
00411         }
00412 }
00413 
00414 /* settings for 'rotation difference' driver variable type */
00415 static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
00416 {
00417         DriverTarget *dtar= &dvar->targets[0];
00418         DriverTarget *dtar2= &dvar->targets[1];
00419         Object *ob1 = (Object *)dtar->id;
00420         Object *ob2 = (Object *)dtar2->id;
00421         PointerRNA dtar_ptr, dtar2_ptr;
00422         uiLayout *col;
00423         
00424         /* initialise RNA pointer to the target */
00425         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
00426         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
00427         
00428         /* Bone 1 */
00429         col= uiLayoutColumn(layout, 1);
00430                 uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", "Bone 1:");
00431                 
00432                 if (dtar->id && ob1->pose) {
00433                         PointerRNA tar_ptr;
00434                         
00435                         RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
00436                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
00437                 }
00438         
00439         col= uiLayoutColumn(layout, 1);
00440                 uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", "Bone 2:");
00441                 
00442                 if (dtar2->id && ob2->pose) {
00443                         PointerRNA tar_ptr;
00444                         
00445                         RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
00446                         uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
00447                 }
00448 }
00449 
00450 /* settings for 'location difference' driver variable type */
00451 static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
00452 {
00453         DriverTarget *dtar= &dvar->targets[0];
00454         DriverTarget *dtar2= &dvar->targets[1];
00455         Object *ob1 = (Object *)dtar->id;
00456         Object *ob2 = (Object *)dtar2->id;
00457         PointerRNA dtar_ptr, dtar2_ptr;
00458         uiLayout *col;
00459         
00460         /* initialise RNA pointer to the target */
00461         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
00462         RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr); 
00463         
00464         /* Bone 1 */
00465         col= uiLayoutColumn(layout, 1);
00466                 uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", "Ob/Bone 1:");
00467                 
00468                 if (dtar->id && ob1->pose) {
00469                         PointerRNA tar_ptr;
00470                         
00471                         RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
00472                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
00473                 }
00474                 
00475                 uiItemR(col, &dtar_ptr, "use_local_space_transform", 0, NULL, ICON_NONE);
00476         
00477         col= uiLayoutColumn(layout, 1);
00478                 uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", "Ob/Bone 2:");
00479                 
00480                 if (dtar2->id && ob2->pose) {
00481                         PointerRNA tar_ptr;
00482                         
00483                         RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
00484                         uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
00485                 }
00486                 
00487                 uiItemR(col, &dtar2_ptr, "use_local_space_transform", 0, NULL, ICON_NONE);
00488 }
00489 
00490 /* settings for 'transform channel' driver variable type */
00491 static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar *dvar)
00492 {
00493         DriverTarget *dtar= &dvar->targets[0];
00494         Object *ob = (Object *)dtar->id;
00495         PointerRNA dtar_ptr;
00496         uiLayout *col, *row;
00497         
00498         /* initialise RNA pointer to the target */
00499         RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr); 
00500         
00501         /* properties */
00502         col= uiLayoutColumn(layout, 1);
00503                 uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", "Ob/Bone:");
00504                 
00505                 if (dtar->id && ob->pose) {
00506                         PointerRNA tar_ptr;
00507                         
00508                         RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
00509                         uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
00510                 }
00511                 
00512                 row= uiLayoutRow(layout, 1);
00513                         uiItemR(row, &dtar_ptr, "transform_type", 0, "", ICON_NONE);
00514                         uiItemR(row, &dtar_ptr, "use_local_space_transform", 0, NULL, ICON_NONE);
00515 }
00516 
00517 /* driver settings for active F-Curve (only for 'Drivers' mode) */
00518 static void graph_panel_drivers(const bContext *C, Panel *pa)
00519 {
00520         bAnimListElem *ale;
00521         FCurve *fcu;
00522         ChannelDriver *driver;
00523         DriverVar *dvar;
00524         
00525         PointerRNA driver_ptr;
00526         uiLayout *col;
00527         uiBlock *block;
00528         uiBut *but;
00529         
00530         /* Get settings from context */
00531         if (!graph_panel_context(C, &ale, &fcu))
00532                 return;
00533         driver= fcu->driver;
00534         
00535         /* set event handler for panel */
00536         block= uiLayoutGetBlock(pa->layout); // xxx?
00537         uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL);
00538         
00539         /* general actions - management */
00540         col= uiLayoutColumn(pa->layout, 0);
00541         block= uiLayoutGetBlock(col);
00542                 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");
00543                 uiButSetFunc(but, driver_update_flags_cb, fcu, NULL);
00544                 
00545                 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");
00546                 uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL);
00547                 
00548         /* driver-level settings - type, expressions, and errors */
00549         RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr);
00550         
00551         col= uiLayoutColumn(pa->layout, 1);
00552         block= uiLayoutGetBlock(col);
00553                 uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE);
00554                 
00555                 /* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */
00556                 if (driver->type == DRIVER_TYPE_PYTHON) {
00557                         /* expression */
00558                         uiItemR(col, &driver_ptr, "expression", 0, "Expr", ICON_NONE);
00559                         
00560                         /* errors? */
00561                         if (driver->flag & DRIVER_FLAG_INVALID)
00562                                 uiItemL(col, "ERROR: invalid Python expression", ICON_ERROR);
00563                 }
00564                 else {
00565                         /* errors? */
00566                         if (driver->flag & DRIVER_FLAG_INVALID)
00567                                 uiItemL(col, "ERROR: invalid target channel(s)", ICON_ERROR);
00568                 }
00569                 
00570         col= uiLayoutColumn(pa->layout, 1);
00571                 /* debug setting */
00572                 uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE);
00573                 
00574                 /* value of driver */
00575                 if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
00576                         uiLayout *row= uiLayoutRow(col, 1);
00577                         char valBuf[32];
00578                         
00579                         uiItemL(row, "Driver Value:", ICON_NONE);
00580                         
00581                         sprintf(valBuf, "%.3f", driver->curval);
00582                         uiItemL(row, valBuf, ICON_NONE);
00583                 }
00584         
00585         /* add driver variables */
00586         col= uiLayoutColumn(pa->layout, 0);
00587         block= uiLayoutGetBlock(col);
00588                 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");
00589                 uiButSetFunc(but, driver_add_var_cb, driver, NULL);
00590         
00591         /* loop over targets, drawing them */
00592         for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
00593                 PointerRNA dvar_ptr;
00594                 uiLayout *box, *row;
00595                 
00596                 /* sub-layout column for this variable's settings */
00597                 col= uiLayoutColumn(pa->layout, 1);
00598                 
00599                 /* header panel */
00600                 box= uiLayoutBox(col);
00601                         /* first row context info for driver */
00602                         RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
00603                         
00604                         row= uiLayoutRow(box, 0);
00605                         block= uiLayoutGetBlock(row);
00606                                 /* variable name */
00607                                 uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
00608                                 
00609                                 /* remove button */
00610                                 uiBlockSetEmboss(block, UI_EMBOSSN);
00611                                         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.");
00612                                         uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
00613                                 uiBlockSetEmboss(block, UI_EMBOSS);
00614                         
00615                         /* variable type */
00616                         row= uiLayoutRow(box, 0);
00617                                 uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
00618                                 
00619                 /* variable type settings */
00620                 box= uiLayoutBox(col);
00621                         /* controls to draw depends on the type of variable */
00622                         switch (dvar->type) {
00623                                 case DVAR_TYPE_SINGLE_PROP:     /* single property */
00624                                         graph_panel_driverVar__singleProp(box, ale->id, dvar);
00625                                         break;
00626                                 case DVAR_TYPE_ROT_DIFF: /* rotational difference */
00627                                         graph_panel_driverVar__rotDiff(box, ale->id, dvar);
00628                                         break;
00629                                 case DVAR_TYPE_LOC_DIFF: /* location difference */
00630                                         graph_panel_driverVar__locDiff(box, ale->id, dvar);
00631                                         break;
00632                                 case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */
00633                                         graph_panel_driverVar__transChan(box, ale->id, dvar);
00634                                         break;
00635                         }
00636                         
00637                 /* value of variable */
00638                 if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
00639                         char valBuf[32];
00640                         
00641                         box= uiLayoutBox(col);
00642                         row= uiLayoutRow(box, 1);
00643                                 uiItemL(row, "Value:", ICON_NONE);
00644                                 
00645                                 sprintf(valBuf, "%.3f", dvar->curval);
00646                                 uiItemL(row, valBuf, ICON_NONE);
00647                 }
00648         }
00649         
00650         /* cleanup */
00651         MEM_freeN(ale);
00652 }
00653 
00654 /* ******************* f-modifiers ******************************** */
00655 /* all the drawing code is in editors/animation/fmodifier_ui.c */
00656 
00657 #define B_FMODIFIER_REDRAW              20
00658 
00659 static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int event)
00660 {
00661         switch (event) {
00662                 case B_REDR:
00663                 case B_FMODIFIER_REDRAW: // XXX this should send depsgraph updates too
00664                         WM_event_add_notifier(C, NC_ANIMATION, NULL); // XXX need a notifier specially for F-Modifiers
00665                         break;
00666         }
00667 }
00668 
00669 static void graph_panel_modifiers(const bContext *C, Panel *pa) 
00670 {
00671         bAnimListElem *ale;
00672         FCurve *fcu;
00673         FModifier *fcm;
00674         uiLayout *col, *row;
00675         uiBlock *block;
00676         
00677         if (!graph_panel_context(C, &ale, &fcu))
00678                 return;
00679         
00680         block= uiLayoutGetBlock(pa->layout);
00681         uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
00682         
00683         /* 'add modifier' button at top of panel */
00684         {
00685                 row= uiLayoutRow(pa->layout, 0);
00686                 block= uiLayoutGetBlock(row);
00687                 
00688                 // XXX for now, this will be a operator button which calls a 'add modifier' operator
00689                 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");
00690                 
00691                 /* copy/paste (as sub-row)*/
00692                 row= uiLayoutRow(row, 1);
00693                         uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
00694                         uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
00695         }
00696         
00697         /* draw each modifier */
00698         for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
00699                 col= uiLayoutColumn(pa->layout, 1);
00700                 
00701                 ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
00702         }
00703 
00704         MEM_freeN(ale);
00705 }
00706 
00707 /* ******************* general ******************************** */
00708 
00709 void graph_buttons_register(ARegionType *art)
00710 {
00711         PanelType *pt;
00712 
00713         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
00714         strcpy(pt->idname, "GRAPH_PT_view");
00715         strcpy(pt->label, "View Properties");
00716         pt->draw= graph_panel_view;
00717         pt->flag |= PNL_DEFAULT_CLOSED;
00718         BLI_addtail(&art->paneltypes, pt);
00719         
00720         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
00721         strcpy(pt->idname, "GRAPH_PT_properties");
00722         strcpy(pt->label, "Active F-Curve");
00723         pt->draw= graph_panel_properties;
00724         pt->poll= graph_panel_poll;
00725         BLI_addtail(&art->paneltypes, pt);
00726         
00727         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
00728         strcpy(pt->idname, "GRAPH_PT_key_properties");
00729         strcpy(pt->label, "Active Keyframe");
00730         pt->draw= graph_panel_key_properties;
00731         pt->poll= graph_panel_poll;
00732         BLI_addtail(&art->paneltypes, pt);
00733 
00734 
00735         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
00736         strcpy(pt->idname, "GRAPH_PT_drivers");
00737         strcpy(pt->label, "Drivers");
00738         pt->draw= graph_panel_drivers;
00739         pt->poll= graph_panel_drivers_poll;
00740         BLI_addtail(&art->paneltypes, pt);
00741 
00742         pt= MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
00743         strcpy(pt->idname, "GRAPH_PT_modifiers");
00744         strcpy(pt->label, "Modifiers");
00745         pt->draw= graph_panel_modifiers;
00746         pt->poll= graph_panel_poll;
00747         BLI_addtail(&art->paneltypes, pt);
00748 }
00749 
00750 static int graph_properties(bContext *C, wmOperator *UNUSED(op))
00751 {
00752         ScrArea *sa= CTX_wm_area(C);
00753         ARegion *ar= graph_has_buttons_region(sa);
00754         
00755         if(ar)
00756                 ED_region_toggle_hidden(C, ar);
00757 
00758         return OPERATOR_FINISHED;
00759 }
00760 
00761 void GRAPH_OT_properties(wmOperatorType *ot)
00762 {
00763         ot->name= "Properties";
00764         ot->idname= "GRAPH_OT_properties";
00765         ot->description= "Toggle display properties panel";
00766         
00767         ot->exec= graph_properties;
00768         ot->poll= ED_operator_graphedit_active;
00769 
00770         /* flags */
00771         ot->flag= 0;
00772 }