diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-02-28 16:27:45 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-02-28 16:27:45 +0300 |
commit | bab4cd69913eee9aa30d61db7dc46e21655e4bde (patch) | |
tree | ebf28a1372c0db195928a1724b05f56d5c62d35e /source/blender/python/intern | |
parent | 0f8969640ccb5e7f615c85576e569ba23dd62c6f (diff) |
Python experimental UI API
Can draw panels in the scripts space containing RNA and operator buttons.
* Added bpyui.register() so scripts can draw buttons and panels into the scripts space type.
* wrapped drawBlock, drawPanels and matchPanelsView2d
* Operator buttons take a python dictionary used to set the button defaults.
* BPY_getFileAndNum utility function to get the filename and line number python is currently running.
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r-- | source/blender/python/intern/bpy_interface.c | 130 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator.h | 3 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_ui.c | 128 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.c | 40 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.h | 2 |
5 files changed, 296 insertions, 7 deletions
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 17802ec3a29..fcf748c6887 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -12,6 +12,9 @@ #include "bpy_rna.h" #include "bpy_operator.h" +#include "bpy_ui.h" + +#include "DNA_space_types.h" /***************************************************************************** @@ -107,3 +110,130 @@ void BPY_run_python_script( bContext *C, const char *fn ) //BPY_end_python(); } + + +/* TODO - move into bpy_space.c ? */ +/* GUI interface routines */ + +/* Copied from Draw.c */ +static void exit_pydraw( SpaceScript * sc, short err ) +{ + Script *script = NULL; + + if( !sc || !sc->script ) + return; + + script = sc->script; + + if( err ) { + PyErr_Print( ); + script->flags = 0; /* mark script struct for deletion */ + SCRIPT_SET_NULL(script); + script->scriptname[0] = '\0'; + script->scriptarg[0] = '\0'; +// XXX 2.5 error_pyscript(); +// XXX 2.5 scrarea_queue_redraw( sc->area ); + } + +#if 0 // XXX 2.5 + BPy_Set_DrawButtonsList(sc->but_refs); + BPy_Free_DrawButtonsList(); /*clear all temp button references*/ +#endif + + sc->but_refs = NULL; + + Py_XDECREF( ( PyObject * ) script->py_draw ); + Py_XDECREF( ( PyObject * ) script->py_event ); + Py_XDECREF( ( PyObject * ) script->py_button ); + + script->py_draw = script->py_event = script->py_button = NULL; +} + +static int bpy_run_script_init(bContext *C, SpaceScript * sc) +{ + if (sc->script==NULL) + return 0; + + if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0') + BPY_run_python_script(C, sc->script->scriptname); + + if (sc->script->py_draw==NULL) + return 0; + + return 1; +} + +int BPY_run_script_space_draw(bContext *C, SpaceScript * sc) +{ + if (bpy_run_script_init(C, sc)) { + PyGILState_STATE gilstate = PyGILState_Ensure(); + PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL ); + PyGILState_Release(gilstate); + + if (result==NULL) + exit_pydraw(sc, 1); + } + return 1; +} + +// XXX - not used yet, listeners dont get a context +int BPY_run_script_space_listener(bContext *C, SpaceScript * sc) +{ + if (bpy_run_script_init(C, sc)) { + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL ); + PyGILState_Release(gilstate); + + if (result==NULL) + exit_pydraw(sc, 1); + } + return 1; +} + +#if 0 +/* called from the the scripts window, assume context is ok */ +int BPY_run_python_script_space(const char *modulename, const char *func) +{ + PyObject *py_dict, *py_result= NULL; + char pystring[512]; + PyGILState_STATE gilstate; + + /* for calling the module function */ + PyObject *py_func, + + gilstate = PyGILState_Ensure(); + + py_dict = CreateGlobalDictionary(C); + + PyObject *module = PyImport_ImportModule(scpt->script.filename); + if (module==NULL) { + PyErr_SetFormat(PyExc_SystemError, "could not import '%s'", scpt->script.filename); + } + else { + py_func = PyObject_GetAttrString(modulename, func); + if (py_func==NULL) { + PyErr_SetFormat(PyExc_SystemError, "module has no function '%s.%s'\n", scpt->script.filename, func); + } + else { + if (!PyCallable_Check(py_func)) { + PyErr_SetFormat(PyExc_SystemError, "module item is not callable '%s.%s'\n", scpt->script.filename, func); + } + else { + py_result= PyObject_CallObject(py_func, NULL); // XXX will need args eventually + } + } + } + + if (!py_result) + PyErr_Print(); + else + Py_DECREF( py_result ); + + Py_XDECREF(module); + + + PyGILState_Release(gilstate); + return 1; +} +#endif diff --git a/source/blender/python/intern/bpy_operator.h b/source/blender/python/intern/bpy_operator.h index fa12857fe19..2dfd17bb01b 100644 --- a/source/blender/python/intern/bpy_operator.h +++ b/source/blender/python/intern/bpy_operator.h @@ -35,8 +35,9 @@ extern PyTypeObject pyop_base_Type; extern PyTypeObject pyop_func_Type; +#define BPy_OperatorBase_Check(v) (PyObject_TypeCheck(v, &pyop_base_Type)) #define BPy_OperatorFunc_Check(v) (PyObject_TypeCheck(v, &pyop_func_Type)) -#define BPy_PropertyRNA_Check(v) (PyObject_TypeCheck(v, &pyop_func_Type)) + typedef struct { PyObject_HEAD /* required python macro */ diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c index 946d9ec6185..a8b57e1aab6 100644 --- a/source/blender/python/intern/bpy_ui.c +++ b/source/blender/python/intern/bpy_ui.c @@ -23,8 +23,11 @@ */ #include "bpy_ui.h" +#include "bpy_util.h" #include "bpy_rna.h" /* for rna buttons */ +#include "bpy_operator.h" /* for setting button operator properties */ #include "bpy_compat.h" +#include "WM_types.h" /* for WM_OP_INVOKE_DEFAULT & friends */ #include "BLI_dynstr.h" @@ -33,6 +36,7 @@ #include "BKE_context.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" /* only for SpaceLink */ #include "UI_interface.h" #include "WM_api.h" @@ -74,14 +78,23 @@ static PyObject *Method_menuItemO( PyObject * self, PyObject * args ) static PyObject *Method_defButO( PyObject * self, PyObject * args ) { - PyObject *py_block; + uiBut *but; + PyObject *py_block, *py_keywords= NULL; char *opname, *butname, *tip; int exec, xco, yco, width, height; - if( !PyArg_ParseTuple( args, "O!sisiiiis:defButO", &PyCObject_Type, &py_block, &opname, &exec, &butname, &xco, &yco, &width, &height, &tip)) + if( !PyArg_ParseTuple( args, "O!sisiiiis|O!:defButO", &PyCObject_Type, &py_block, &opname, &exec, &butname, &xco, &yco, &width, &height, &tip, &PyDict_Type, &py_keywords)) return NULL; - return PyCObject_FromVoidPtr(uiDefButO(PyCObject_AsVoidPtr(py_block), BUT, opname, exec, butname, xco, yco, width, height, tip), NULL ); + but= uiDefButO(PyCObject_AsVoidPtr(py_block), BUT, opname, exec, butname, xco, yco, width, height, tip); + + /* Optional python doctionary used to set python properties, just like how keyword args are used */ + if (py_keywords && PyDict_Size(py_keywords)) { + if (PYOP_props_from_dict(uiButGetOperatorPtrRNA(but), py_keywords) == -1) + return NULL; + } + + return PyCObject_FromVoidPtr(but, NULL); } static PyObject *Method_defAutoButR( PyObject * self, PyObject * args ) @@ -165,6 +178,40 @@ static PyObject *Method_endBlock( PyObject * self, PyObject * args ) Py_RETURN_NONE; } +static PyObject *Method_drawBlock( PyObject * self, PyObject * args ) +{ + PyObject *py_context, *py_block; + + if( !PyArg_ParseTuple( args, "O!O!:drawBlock", &PyCObject_Type, &py_context, &PyCObject_Type, &py_block) ) + return NULL; + + uiDrawBlock(PyCObject_AsVoidPtr(py_context), PyCObject_AsVoidPtr(py_block)); + Py_RETURN_NONE; +} + +static PyObject *Method_drawPanels( PyObject * self, PyObject * args ) +{ + PyObject *py_context; + int align; + + if( !PyArg_ParseTuple( args, "O!i:drawPanels", &PyCObject_Type, &py_context, &align) ) + return NULL; + + uiDrawPanels(PyCObject_AsVoidPtr(py_context), align); + Py_RETURN_NONE; +} + +static PyObject *Method_matchPanelsView2d( PyObject * self, PyObject * args ) +{ + PyObject *py_ar; + + if( !PyArg_ParseTuple( args, "O!:matchPanelsView2d", &PyCObject_Type, &py_ar) ) + return NULL; + + uiMatchPanelsView2d(PyCObject_AsVoidPtr(py_ar)); + Py_RETURN_NONE; +} + static PyObject *Method_popupBoundsBlock( PyObject * self, PyObject * args ) { PyObject *py_block; @@ -223,6 +270,55 @@ static PyObject *Method_newPanel( PyObject * self, PyObject * args ) return PyLong_FromSize_t(uiNewPanel(PyCObject_AsVoidPtr(py_context), PyCObject_AsVoidPtr(py_area), PyCObject_AsVoidPtr(py_block), panelname, tabname, ofsx, ofsy, sizex, sizey)); } +/* similar to Draw.c */ +static PyObject *Method_register( PyObject * self, PyObject * args ) +{ + PyObject *py_sl, *py_draw_func; + SpaceLink *sl; + if( !PyArg_ParseTuple( args, "O!O:register", &PyCObject_Type, &py_sl, &py_draw_func) ) + return NULL; + + sl = PyCObject_AsVoidPtr(py_sl); + + if(sl->spacetype!=SPACE_SCRIPT) { // XXX todo - add a script space when needed + PyErr_SetString(PyExc_ValueError, "can only register in a script space"); + return NULL; + } + else { + SpaceScript *scpt= (SpaceScript *)sl; + char *filename = NULL; + + if (scpt->script==NULL) { + scpt->script = MEM_callocN(sizeof(Script), "ScriptRegister"); + } + + BPY_getFileAndNum(&filename, NULL); + + if (filename) { + strncpy(scpt->script->scriptname, filename, sizeof(scpt->script->scriptname)); +#if 0 + char *dot; + dot = strchr(scpt->script->scriptname, '.'); /* remove extension */ + if (dot) + *dot= '\0'; +#endif + Py_XINCREF( py_draw_func ); + scpt->script->py_draw= (void *)py_draw_func; + } + else { + return NULL; /* BPY_getFileAndNum sets the error */ + } + + if (filename==NULL) { + return NULL; + } + } + + Py_RETURN_NONE; +} + + + /* internal use only */ static bContext *get_py_context__internal(void) { @@ -255,6 +351,14 @@ static PyObject *Method_getScreenPtr( PyObject * self ) return PyCObject_FromVoidPtr(screen, NULL); } +static PyObject *Method_getSpacePtr( PyObject * self ) +{ + bContext *C= get_py_context__internal(); + + SpaceLink *sl= CTX_wm_space_data(C); + return PyCObject_FromVoidPtr(sl, NULL); +} + static PyObject *Method_getWindowPtr( PyObject * self ) { bContext *C= get_py_context__internal(); @@ -272,20 +376,25 @@ static struct PyMethodDef ui_methods[] = { {"pupBlock", (PyCFunction)Method_pupBlock, METH_VARARGS, ""}, {"beginBlock", (PyCFunction)Method_beginBlock, METH_VARARGS, ""}, {"endBlock", (PyCFunction)Method_endBlock, METH_VARARGS, ""}, + {"drawBlock", (PyCFunction)Method_drawBlock, METH_VARARGS, ""}, {"popupBoundsBlock", (PyCFunction)Method_popupBoundsBlock, METH_VARARGS, ""}, {"blockBeginAlign", (PyCFunction)Method_blockBeginAlign, METH_VARARGS, ""}, {"blockEndAlign", (PyCFunction)Method_blockEndAlign, METH_VARARGS, ""}, {"blockSetFlag", (PyCFunction)Method_blockSetFlag, METH_VARARGS, ""}, {"newPanel", (PyCFunction)Method_newPanel, METH_VARARGS, ""}, + {"drawPanels", (PyCFunction)Method_drawPanels, METH_VARARGS, ""}, + {"matchPanelsView2d", (PyCFunction)Method_matchPanelsView2d, METH_VARARGS, ""}, + + {"register", (PyCFunction)Method_register, METH_VARARGS, ""}, // XXX not sure about this - registers current script with the ScriptSpace, like Draw.Register() {"getRegonPtr", (PyCFunction)Method_getRegonPtr, METH_NOARGS, ""}, // XXX Nasty, we really need to improve dealing with context! {"getAreaPtr", (PyCFunction)Method_getAreaPtr, METH_NOARGS, ""}, {"getScreenPtr", (PyCFunction)Method_getScreenPtr, METH_NOARGS, ""}, + {"getSpacePtr", (PyCFunction)Method_getSpacePtr, METH_NOARGS, ""}, {"getWindowPtr", (PyCFunction)Method_getWindowPtr, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} }; -#if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef ui_module = { PyModuleDef_HEAD_INIT, "bpyui", @@ -294,7 +403,6 @@ static struct PyModuleDef ui_module = { ui_methods, NULL, NULL, NULL, NULL }; -#endif PyObject *BPY_ui_module( void ) { @@ -316,6 +424,16 @@ PyObject *BPY_ui_module( void ) PyModule_AddObject( submodule, "UI_BLOCK_KEEP_OPEN", PyLong_FromSize_t(UI_BLOCK_KEEP_OPEN) ); PyModule_AddObject( submodule, "UI_BLOCK_POPUP", PyLong_FromSize_t(UI_BLOCK_POPUP) ); + /* for executing operators (XXX move elsewhere) */ + PyModule_AddObject( submodule, "WM_OP_INVOKE_DEFAULT", PyLong_FromSize_t(WM_OP_INVOKE_DEFAULT) ); + PyModule_AddObject( submodule, "WM_OP_INVOKE_REGION_WIN", PyLong_FromSize_t(WM_OP_INVOKE_REGION_WIN) ); + PyModule_AddObject( submodule, "WM_OP_INVOKE_AREA", PyLong_FromSize_t(WM_OP_INVOKE_AREA) ); + PyModule_AddObject( submodule, "WM_OP_INVOKE_SCREEN", PyLong_FromSize_t(WM_OP_INVOKE_SCREEN) ); + PyModule_AddObject( submodule, "WM_OP_EXEC_DEFAULT", PyLong_FromSize_t(WM_OP_EXEC_DEFAULT) ); + PyModule_AddObject( submodule, "WM_OP_EXEC_REGION_WIN", PyLong_FromSize_t(WM_OP_EXEC_REGION_WIN) ); + PyModule_AddObject( submodule, "WM_OP_EXEC_AREA", PyLong_FromSize_t(WM_OP_EXEC_AREA) ); + PyModule_AddObject( submodule, "WM_OP_EXEC_SCREEN", PyLong_FromSize_t(WM_OP_EXEC_SCREEN) ); + return submodule; } diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 63112295d18..31d15d8a69e 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -161,3 +161,43 @@ void PyObSpit(char *name, PyObject *var) { } fprintf(stderr, "\n"); } + +void BPY_getFileAndNum(char **filename, int *lineno) +{ + PyObject *getframe, *frame; + PyObject *f_lineno, *f_code, *co_filename; + + if (filename) *filename= NULL; + if (lineno) *lineno = -1; + + getframe = PySys_GetObject("_getframe"); // borrowed + if (getframe) { + frame = PyObject_CallObject(getframe, NULL); + if (frame) { + f_lineno= PyObject_GetAttrString(frame, "f_lineno"); + f_code= PyObject_GetAttrString(frame, "f_code"); + if (f_lineno && f_code) { + co_filename= PyObject_GetAttrString(f_code, "co_filename"); + if (co_filename) { + + if (filename) *filename = _PyUnicode_AsString(co_filename); + if (lineno) *lineno = (int)PyLong_AsSsize_t(f_lineno); + + Py_DECREF(f_lineno); + Py_DECREF(f_code); + Py_DECREF(co_filename); + Py_DECREF(frame); + + return; + } + } + } + } + + Py_XDECREF(co_filename); + Py_XDECREF(f_lineno); + Py_XDECREF(f_code); + Py_XDECREF(frame); + + PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename"); +} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 82cc602fcab..4b0af975025 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -35,4 +35,4 @@ PyObject *BPY_flag_to_list(BPY_flag_def *flagdef, int flag); int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag); void PyObSpit(char *name, PyObject *var); - +void BPY_getFileAndNum(char **filename, int *lineno); |