/* driver settings for active F-Curve (only for 'Drivers' mode) */ static void graph_panel_drivers(const bContext *C, Panel *pa) { bAnimListElem *ale; FCurve *fcu; ChannelDriver *driver; DriverVar *dvar; PointerRNA driver_ptr; uiLayout *col; uiBlock *block; uiBut *but; /* Get settings from context */ if (!graph_panel_context(C, &ale, &fcu)) return; driver = fcu->driver; /* set event handler for panel */ block = uiLayoutGetBlock(pa->layout); // xxx? uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL); /* general actions - management */ col = uiLayoutColumn(pa->layout, FALSE); block = uiLayoutGetBlock(col); but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Update Dependencies"), 0, 0, 10 * UI_UNIT_X, 22, NULL, 0.0, 0.0, 0, 0, TIP_("Force updates of dependencies")); uiButSetFunc(but, driver_update_flags_cb, fcu, NULL); but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Remove Driver"), 0, 0, 10 * UI_UNIT_X, 18, NULL, 0.0, 0.0, 0, 0, TIP_("Remove this driver")); uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL); /* driver-level settings - type, expressions, and errors */ RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr); col = uiLayoutColumn(pa->layout, TRUE); block = uiLayoutGetBlock(col); uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE); /* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */ if (driver->type == DRIVER_TYPE_PYTHON) { /* expression */ uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE); /* errors? */ if (driver->flag & DRIVER_FLAG_INVALID) uiItemL(col, IFACE_("ERROR: invalid Python expression"), ICON_ERROR); } else { /* errors? */ if (driver->flag & DRIVER_FLAG_INVALID) uiItemL(col, IFACE_("ERROR: invalid target channel(s)"), ICON_ERROR); } col = uiLayoutColumn(pa->layout, TRUE); /* debug setting */ uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE); /* value of driver */ if (driver->flag & DRIVER_FLAG_SHOWDEBUG) { uiLayout *row = uiLayoutRow(col, TRUE); char valBuf[32]; uiItemL(row, IFACE_("Driver Value:"), ICON_NONE); BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval); uiItemL(row, valBuf, ICON_NONE); } /* add driver variables */ col = uiLayoutColumn(pa->layout, FALSE); block = uiLayoutGetBlock(col); but = uiDefBut(block, BUT, B_IPO_DEPCHANGE, IFACE_("Add Variable"), 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Add a new target variable for this Driver")); uiButSetFunc(but, driver_add_var_cb, driver, NULL); /* loop over targets, drawing them */ for (dvar = driver->variables.first; dvar; dvar = dvar->next) { PointerRNA dvar_ptr; uiLayout *box, *row; /* sub-layout column for this variable's settings */ col = uiLayoutColumn(pa->layout, TRUE); /* header panel */ box = uiLayoutBox(col); /* first row context info for driver */ RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr); row = uiLayoutRow(box, FALSE); block = uiLayoutGetBlock(row); /* variable name */ uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE); /* remove button */ uiBlockSetEmboss(block, UI_EMBOSSN); 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, IFACE_("Delete target variable")); uiButSetFunc(but, driver_delete_var_cb, driver, dvar); uiBlockSetEmboss(block, UI_EMBOSS); /* variable type */ row = uiLayoutRow(box, FALSE); uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE); /* variable type settings */ box = uiLayoutBox(col); /* controls to draw depends on the type of variable */ switch (dvar->type) { case DVAR_TYPE_SINGLE_PROP: /* single property */ graph_panel_driverVar__singleProp(box, ale->id, dvar); break; case DVAR_TYPE_ROT_DIFF: /* rotational difference */ graph_panel_driverVar__rotDiff(box, ale->id, dvar); break; case DVAR_TYPE_LOC_DIFF: /* location difference */ graph_panel_driverVar__locDiff(box, ale->id, dvar); break; case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */ graph_panel_driverVar__transChan(box, ale->id, dvar); break; } /* value of variable */ if (driver->flag & DRIVER_FLAG_SHOWDEBUG) { char valBuf[32]; box = uiLayoutBox(col); row = uiLayoutRow(box, TRUE); uiItemL(row, IFACE_("Value:"), ICON_NONE); BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval); uiItemL(row, valBuf, ICON_NONE); } } /* cleanup */ MEM_freeN(ale); }
/* driver settings for active F-Curve (only for 'Drivers' mode) */ static void graph_panel_drivers(const bContext *C, Panel *pa) { bAnimListElem *ale; FCurve *fcu; ChannelDriver *driver; DriverVar *dvar; PointerRNA driver_ptr; uiLayout *col; uiBlock *block; uiBut *but; /* Get settings from context */ if (!graph_panel_context(C, &ale, &fcu)) return; driver = fcu->driver; /* set event handler for panel */ block = uiLayoutGetBlock(pa->layout); // xxx? uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL); /* general actions - management */ col = uiLayoutColumn(pa->layout, false); block = uiLayoutGetBlock(col); but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_FILE_REFRESH, IFACE_("Update Dependencies"), 0, 0, 10 * UI_UNIT_X, 22, NULL, 0.0, 0.0, 0, 0, TIP_("Force updates of dependencies")); uiButSetFunc(but, driver_update_flags_cb, fcu, NULL); but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_ZOOMOUT, IFACE_("Remove Driver"), 0, 0, 10 * UI_UNIT_X, 18, NULL, 0.0, 0.0, 0, 0, TIP_("Remove this driver")); uiButSetNFunc(but, driver_remove_cb, MEM_dupallocN(ale), NULL); /* driver-level settings - type, expressions, and errors */ RNA_pointer_create(ale->id, &RNA_Driver, driver, &driver_ptr); col = uiLayoutColumn(pa->layout, true); block = uiLayoutGetBlock(col); uiItemR(col, &driver_ptr, "type", 0, NULL, ICON_NONE); /* show expression box if doing scripted drivers, and/or error messages when invalid drivers exist */ if (driver->type == DRIVER_TYPE_PYTHON) { bool bpy_data_expr_error = (strstr(driver->expression, "bpy.data.") != NULL); bool bpy_ctx_expr_error = (strstr(driver->expression, "bpy.context.") != NULL); /* expression */ uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE); /* errors? */ if ((G.f & G_SCRIPT_AUTOEXEC) == 0) { uiItemL(col, IFACE_("ERROR: Python auto-execution disabled"), ICON_CANCEL); } else if (driver->flag & DRIVER_FLAG_INVALID) { uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_CANCEL); } /* Explicit bpy-references are evil. Warn about these to prevent errors */ /* TODO: put these in a box? */ if (bpy_data_expr_error || bpy_ctx_expr_error) { uiItemL(col, IFACE_("WARNING: Driver expression may not work correctly"), ICON_HELP); if (bpy_data_expr_error) { uiItemL(col, IFACE_("TIP: Use variables instead of bpy.data paths (see below)"), ICON_ERROR); } if (bpy_ctx_expr_error) { uiItemL(col, IFACE_("TIP: bpy.context is not safe for renderfarm usage"), ICON_ERROR); } } } else { /* errors? */ if (driver->flag & DRIVER_FLAG_INVALID) uiItemL(col, IFACE_("ERROR: Invalid target channel(s)"), ICON_ERROR); /* Warnings about a lack of variables * NOTE: The lack of variables is generally a bad thing, since it indicates * that the driver doesn't work at all. This particular scenario arises * primarily when users mistakenly try to use drivers for procedural * property animation */ if (BLI_listbase_is_empty(&driver->variables)) { uiItemL(col, IFACE_("ERROR: Driver is useless without any inputs"), ICON_ERROR); if (!BLI_listbase_is_empty(&fcu->modifiers)) { uiItemL(col, IFACE_("TIP: Use F-Curves for procedural animation instead"), ICON_INFO); uiItemL(col, IFACE_("F-Modifiers can generate curves for those too"), ICON_INFO); } } } col = uiLayoutColumn(pa->layout, true); /* debug setting */ uiItemR(col, &driver_ptr, "show_debug_info", 0, NULL, ICON_NONE); /* value of driver */ if (driver->flag & DRIVER_FLAG_SHOWDEBUG) { uiLayout *row = uiLayoutRow(col, true); char valBuf[32]; uiItemL(row, IFACE_("Driver Value:"), ICON_NONE); BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", driver->curval); uiItemL(row, valBuf, ICON_NONE); } /* add driver variables */ col = uiLayoutColumn(pa->layout, false); block = uiLayoutGetBlock(col); but = uiDefIconTextBut(block, BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"), 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly")); uiButSetFunc(but, driver_add_var_cb, driver, NULL); /* loop over targets, drawing them */ for (dvar = driver->variables.first; dvar; dvar = dvar->next) { PointerRNA dvar_ptr; uiLayout *box, *row; /* sub-layout column for this variable's settings */ col = uiLayoutColumn(pa->layout, true); /* header panel */ box = uiLayoutBox(col); /* first row context info for driver */ RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr); row = uiLayoutRow(box, false); block = uiLayoutGetBlock(row); /* variable name */ uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE); /* remove button */ uiBlockSetEmboss(block, UI_EMBOSSN); 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, IFACE_("Delete target variable")); uiButSetFunc(but, driver_delete_var_cb, driver, dvar); uiBlockSetEmboss(block, UI_EMBOSS); /* variable type */ row = uiLayoutRow(box, false); uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE); /* variable type settings */ box = uiLayoutBox(col); /* controls to draw depends on the type of variable */ switch (dvar->type) { case DVAR_TYPE_SINGLE_PROP: /* single property */ graph_panel_driverVar__singleProp(box, ale->id, dvar); break; case DVAR_TYPE_ROT_DIFF: /* rotational difference */ graph_panel_driverVar__rotDiff(box, ale->id, dvar); break; case DVAR_TYPE_LOC_DIFF: /* location difference */ graph_panel_driverVar__locDiff(box, ale->id, dvar); break; case DVAR_TYPE_TRANSFORM_CHAN: /* transform channel */ graph_panel_driverVar__transChan(box, ale->id, dvar); break; } /* value of variable */ if (driver->flag & DRIVER_FLAG_SHOWDEBUG) { char valBuf[32]; box = uiLayoutBox(col); row = uiLayoutRow(box, true); uiItemL(row, IFACE_("Value:"), ICON_NONE); if ((dvar->type == DVAR_TYPE_ROT_DIFF) || (dvar->type == DVAR_TYPE_TRANSFORM_CHAN && dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX && dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) { BLI_snprintf(valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval)); } else { BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval); } uiItemL(row, valBuf, ICON_NONE); } } /* cleanup */ MEM_freeN(ale); }