diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h index 9e1870ac36f..4ae25a44b94 100644 --- a/source/blender/blenkernel/BKE_bad_level_calls.h +++ b/source/blender/blenkernel/BKE_bad_level_calls.h @@ -71,6 +71,8 @@ void BPY_free_screen_spacehandlers (struct bScreen *sc); struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver); float BPY_pydriver_eval(struct IpoDriver *driver); void BPY_pydriver_update(void); +/* button python evaluation */ +int BPY_button_eval(char *expr, double *value); /* writefile.c */ struct Oops; diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index f6f5ad193cc..b927cbe98ef 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -114,12 +114,15 @@ float BPY_pydriver_eval(struct IpoDriver *driver) { return 0; } - /* depsgraph.c: */ struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver) { return 0; } +int BPY_button_eval(char *expr, double *value) +{ + return 0; +} /* writefile.c */ /* struct Oops; */ diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index b2c6287f9b3..d7db680a458 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -85,6 +85,8 @@ extern "C" { float BPY_pydriver_eval(struct IpoDriver *driver); struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver); + int BPY_button_eval(char *expr, double *value); + /* format importer hook */ int BPY_call_importloader( char *name ); diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index e6514fca7bf..8f959d660df 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -1144,6 +1144,74 @@ float BPY_pydriver_eval(IpoDriver *driver) return result; } +/* Button Python Evaluation */ + +/* Python evaluation for gui buttons: + * users can write any valid Python expression (that evals to an int or float) + * inside Blender's gui number buttons and have them evaluated to their + * actual int or float value. + * + * The global dict used for pydrivers is also used here, so all imported + * modules for pydrivers (including the pydrivers.py Blender text) are + * available for button py eval, too. */ + +static int bpy_button_eval_error(char *expr) { + + if (bpy_pydriver_oblist) + bpy_pydriver_freeList(); + + if (bpy_pydriver_Dict) { /* free the persistent global dict */ + /* it's the same dict used by pydrivers */ + PyDict_Clear(bpy_pydriver_Dict); + Py_DECREF(bpy_pydriver_Dict); + bpy_pydriver_Dict = NULL; + } + + fprintf(stderr, "\nError in button evaluation:\nThis is the failed Python expression:\n'%s'\n\n", expr); + + PyErr_Print(); + + return -1; +} + +int BPY_button_eval(char *expr, double *value) +{ + PyObject *retval, *floatval; + + if (!value || !expr || expr[0]=='\0') return -1; + + *value = 0.0; /* default value */ + + if (!bpy_pydriver_Dict) { + if (bpy_pydriver_create_dict() != 0) { + fprintf(stderr, + "Button Python Eval error: couldn't create Python dictionary"); + return -1; + } + } + + retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, + bpy_pydriver_Dict); + + if (retval == NULL) { + return bpy_button_eval_error(expr); + } + else { + floatval = PyNumber_Float(retval); + Py_DECREF(retval); + } + + if (floatval == NULL) + return bpy_button_eval_error(expr); + else { + *value = (float)PyFloat_AsDouble(floatval); + Py_DECREF(floatval); + } + + return 0; /* successful exit */ +} + + /*****************************************************************************/ /* ScriptLinks */ /*****************************************************************************/ diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c index 9fa8ca3e25b..cad852aae0d 100644 --- a/source/blender/src/interface.c +++ b/source/blender/src/interface.c @@ -99,6 +99,8 @@ #include "BSE_view.h" +#include "BPY_extern.h" /* for BPY_button_eval */ + #include "mydevice.h" #include "interface.h" #include "blendef.h" @@ -2007,7 +2009,7 @@ static int ui_act_as_text_but(uiBut *but) min= but->min; max= but->max; but->min= 0.0; - but->max= 15.0; + but->max= UI_MAX_DRAW_STR - 1; /* for py strings evaluation */ temp= but->type; but->type= TEX; textleft= but->flag & UI_TEXT_LEFT; @@ -2024,8 +2026,15 @@ static int ui_act_as_text_but(uiBut *but) but->max= max; if(textleft==0) but->flag &= ~UI_TEXT_LEFT; - if( but->pointype==FLO ) value= atof(str); - else value= atoi(str); + if(str[0] == '#') { + if(BPY_button_eval(str+1, &value)) { /* str+1 to skip the # sign */ + error("Invalid Python expression, check console"); + retval = 0; /* invalidate return value if eval failed */ + } + } + else value = atof(str); + + if(but->pointype!=FLO) value= (int)value; if(valuemax) value= max;