diff options
18 files changed, 300 insertions, 154 deletions
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 47622611cb9..9d2830983e1 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -41,7 +41,6 @@ #include "BKE_context.h" #include "BKE_main.h" -#include "BKE_report.h" #include "BKE_screen.h" #include <string.h> diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 483876e5e05..2f3ca52a09e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -56,7 +56,22 @@ static void spacetype_free(SpaceType *st) for(art= st->regiontypes.first; art; art= art->next) { BLI_freelistN(&art->drawcalls); +#ifdef DISABLE_PYTHON BLI_freelistN(&art->paneltypes); +#else + { + PanelType *pnl, *pnl_next; + for(pnl= art->paneltypes.first; pnl; pnl= pnl_next) { + pnl_next= pnl->next; + + if(pnl->py_data) + BPY_DECREF(pnl->py_data); + + MEM_freeN(pnl); + } + art->paneltypes.first= art->paneltypes.last= NULL; + } +#endif BLI_freelistN(&art->headertypes); } diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 53b50460d1d..35706308ed7 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -43,6 +43,7 @@ struct bDeformGroup; struct MDeformWeight; struct MDeformVert; struct Scene; +struct Mesh; struct MCol; struct UvVertMap; struct UvMapVert; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index cde4c4d6867..1bc898016e6 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -456,6 +456,10 @@ int RNA_enum_get(PointerRNA *ptr, const char *name); void RNA_enum_set(PointerRNA *ptr, const char *name, int value); int RNA_enum_is_equal(PointerRNA *ptr, const char *name, const char *enumname); +/* lower level functions that donr use a PointerRNA */ +int RNA_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value); +int RNA_enum_id_from_value(EnumPropertyItem *item, int value, const char **identifier); + void RNA_string_get(PointerRNA *ptr, const char *name, char *value); char *RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen); int RNA_string_length(PointerRNA *ptr, const char *name); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 9cb49fcaf60..f8c0ba18c29 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -30,6 +30,8 @@ /* Types */ extern EnumPropertyItem prop_mode_items[]; +extern EnumPropertyItem space_type_items[]; +extern EnumPropertyItem region_type_items[]; #endif /* RNA_ENUM_TYPES */ diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 52b1b77ddf0..cf6072c2bfd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1832,6 +1832,32 @@ int RNA_enum_is_equal(PointerRNA *ptr, const char *name, const char *enumname) } } +int RNA_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value) +{ + for( ; item->identifier; item++) { + if (strcmp(item->identifier, identifier)==0) { + *value= item->value; + return 1; + } + } + + return 0; +} + +int RNA_enum_id_from_value(EnumPropertyItem *item, int value, const char **identifier) +{ + for( ; item->identifier; item++) { + if (item->value==value) { + *identifier= item->identifier; + return 1; + } + } + + return 0; +} + + + void RNA_string_get(PointerRNA *ptr, const char *name, char *value) { PropertyRNA *prop= RNA_struct_find_property(ptr, name); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 9508357233c..00cf29bfc51 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -32,6 +32,14 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" +EnumPropertyItem region_type_items[] = { + {RGN_TYPE_WINDOW, "WINDOW", "Window", ""}, + {RGN_TYPE_HEADER, "HEADER", "Header", ""}, + {RGN_TYPE_CHANNELS, "CHANNELS", "Channels", ""}, + {RGN_TYPE_TEMPORARY, "TEMPORARY", "Temporary", ""}, + {RGN_TYPE_UI, "BUTTONS_WINDOW", "Window", ""}, + {0, NULL, NULL, NULL}}; + #ifdef RNA_RUNTIME #else diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 5184e904927..9950d70af24 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -33,6 +33,26 @@ #include "WM_types.h" +EnumPropertyItem space_type_items[] = { + {SPACE_EMPTY, "EMPTY", "Empty", ""}, + {SPACE_VIEW3D, "VIEW_3D", "3D View", ""}, + {SPACE_IPO, "GRAPH_EDITOR", "Graph Editor", ""}, + {SPACE_OUTLINER, "OUTLINER", "Outliner", ""}, + {SPACE_BUTS, "BUTTONS_WINDOW", "Buttons Window", ""}, + {SPACE_FILE, "FILE_BROWSER", "File Browser", ""}, + {SPACE_IMAGE, "IMAGE_EDITOR", "Image Editor", ""}, + {SPACE_INFO, "USER_PREFERENCES", "User Preferences", ""}, + {SPACE_SEQ, "SEQUENCE_EDITOR", "Sequence Editor", ""}, + {SPACE_TEXT, "TEXT_EDITOR", "Text Editor", ""}, + //{SPACE_IMASEL, "IMAGE_BROWSER", "Image Browser", ""}, + {SPACE_SOUND, "AUDIO_WINDOW", "Audio Window", ""}, + {SPACE_ACTION, "DOPESHEET_EDITOR", "DopeSheet Editor", ""}, + {SPACE_NLA, "NLA_EDITOR", "NLA Editor", ""}, + {SPACE_SCRIPT, "SCRIPTS_WINDOW", "Scripts Window", ""}, + {SPACE_TIME, "TIMELINE", "Timeline", ""}, + {SPACE_NODE, "NODE_EDITOR", "Node Editor", ""}, + {0, NULL, NULL, NULL}}; + #ifdef RNA_RUNTIME #include "DNA_scene_types.h" @@ -117,26 +137,6 @@ static void rna_def_space(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - - static EnumPropertyItem type_items[] = { - {SPACE_EMPTY, "EMPTY", "Empty", ""}, - {SPACE_VIEW3D, "VIEW_3D", "3D View", ""}, - {SPACE_IPO, "GRAPH_EDITOR", "Graph Editor", ""}, - {SPACE_OUTLINER, "OUTLINER", "Outliner", ""}, - {SPACE_BUTS, "BUTTONS_WINDOW", "Buttons Window", ""}, - {SPACE_FILE, "FILE_BROWSER", "File Browser", ""}, - {SPACE_IMAGE, "IMAGE_EDITOR", "Image Editor", ""}, - {SPACE_INFO, "USER_PREFERENCES", "User Preferences", ""}, - {SPACE_SEQ, "SEQUENCE_EDITOR", "Sequence Editor", ""}, - {SPACE_TEXT, "TEXT_EDITOR", "Text Editor", ""}, - //{SPACE_IMASEL, "IMAGE_BROWSER", "Image Browser", ""}, - {SPACE_SOUND, "AUDIO_WINDOW", "Audio Window", ""}, - {SPACE_ACTION, "DOPESHEET_EDITOR", "DopeSheet Editor", ""}, - {SPACE_NLA, "NLA_EDITOR", "NLA Editor", ""}, - {SPACE_SCRIPT, "SCRIPTS_WINDOW", "Scripts Window", ""}, - {SPACE_TIME, "TIMELINE", "Timeline", ""}, - {SPACE_NODE, "NODE_EDITOR", "Node Editor", ""}, - {0, NULL, NULL, NULL}}; srna= RNA_def_struct(brna, "Space", NULL); RNA_def_struct_sdna(srna, "SpaceLink"); @@ -145,7 +145,7 @@ static void rna_def_space(BlenderRNA *brna) prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spacetype"); - RNA_def_property_enum_items(prop, type_items); + RNA_def_property_enum_items(prop, space_type_items); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Type", "Space data type."); } diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 4b7238a2f7c..690dc7144e6 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -139,7 +139,8 @@ extern "C" { void BPY_scripts_clear_pyobjects( void ); void error_pyscript( void ); - + void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */ + /* void BPY_Err_Handle(struct Text *text); */ /* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */ /* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 94ec8deebe4..f8031368f06 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -241,6 +241,11 @@ int BPY_run_script_space_listener(bContext *C, SpaceScript * sc) return 1; } +void BPY_DECREF(void *pyob_ptr) +{ + Py_DECREF((PyObject *)pyob_ptr); +} + #if 0 /* called from the the scripts window, assume context is ok */ int BPY_run_python_script_space(const char *modulename, const char *func) diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 02f4723c037..29ec3376765 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -24,7 +24,7 @@ */ #include "bpy_operator.h" -#include "bpy_opwrapper.h" +#include "bpy_operator_wrap.h" #include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */ #include "bpy_compat.h" diff --git a/source/blender/python/intern/bpy_opwrapper.c b/source/blender/python/intern/bpy_operator_wrap.c index b7d4c82588e..1db1f547fa6 100644 --- a/source/blender/python/intern/bpy_opwrapper.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -24,7 +24,7 @@ */ -#include "bpy_opwrapper.h" +#include "bpy_operator_wrap.h" #include "BLI_listbase.h" #include "BKE_context.h" #include "BKE_report.h" @@ -45,14 +45,6 @@ #define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */ #define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */ -typedef struct PyOperatorType { - void *next, *prev; - char idname[OP_MAX_TYPENAME]; - char name[OP_MAX_TYPENAME]; - char description[OP_MAX_TYPENAME]; // XXX should be longer? - PyObject *py_class; -} PyOperatorType; - static PyObject *pyop_dict_from_event(wmEvent *event) { PyObject *dict= PyDict_New(); @@ -191,14 +183,16 @@ static struct BPY_flag_def pyop_ret_flags[] = { static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event) { - PyOperatorType *pyot = op->type->pyop_data; + PyObject *py_class = op->type->pyop_data; PyObject *args; PyObject *ret= NULL, *py_class_instance, *item; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); - + + PyGILState_STATE gilstate = PyGILState_Ensure(); + args = PyTuple_New(1); - PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(pyot->py_class, "__rna__")); // need to use an rna instance as the first arg - py_class_instance = PyObject_Call(pyot->py_class, args, NULL); + PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg + py_class_instance = PyObject_Call(py_class, args, NULL); Py_DECREF(args); if (py_class_instance) { /* Initializing the class worked, now run its invoke function */ @@ -229,16 +223,16 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve if (mode==PYOP_INVOKE) { - item= PyObject_GetAttrString(pyot->py_class, "invoke"); + item= PyObject_GetAttrString(py_class, "invoke"); args = PyTuple_New(2); PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); } else if (mode==PYOP_EXEC) { - item= PyObject_GetAttrString(pyot->py_class, "exec"); + item= PyObject_GetAttrString(py_class, "exec"); args = PyTuple_New(1); } else if (mode==PYOP_POLL) { - item= PyObject_GetAttrString(pyot->py_class, "poll"); + item= PyObject_GetAttrString(py_class, "poll"); args = PyTuple_New(2); //XXX Todo - wrap context in a useful way, None for now. PyTuple_SET_ITEM(args, 1, Py_None); @@ -251,7 +245,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(item); } - if (ret == NULL) { + if (ret == NULL) { /* covers py_class_instance failing too */ pyop_error_report(op->reports); } else { @@ -280,6 +274,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(ret); } + PyGILState_Release(gilstate); + return ret_flag; } @@ -302,15 +298,29 @@ static int PYTHON_OT_poll(bContext *C) void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) { - PyOperatorType *pyot = (PyOperatorType *)userdata; - PyObject *py_class = pyot->py_class; + PyObject *py_class = (PyObject *)userdata; PyObject *props, *item; /* identifiers */ - ot->name= pyot->name; - ot->idname= pyot->idname; - ot->description= pyot->description; + item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); + Py_DECREF(item); + ot->idname= _PyUnicode_AsString(item); + + item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME); + if (item) { + Py_DECREF(item); + ot->name= _PyUnicode_AsString(item); + } + else { + ot->name= ot->idname; + PyErr_Clear(); + } + + item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION); + Py_DECREF(item); + ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):""; + /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; @@ -364,105 +374,48 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) /* pyOperators - Operators defined IN Python */ -PyObject *PYOP_wrap_add(PyObject *self, PyObject *value) +PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) { - PyObject *optype, *item; + PyObject *base_class, *item; - PyOperatorType *pyot; - char *idname= NULL; - char *name= NULL; - char *description= NULL; - static char *pyop_func_names[] = {"exec", "invoke", "poll", NULL}; - static int pyop_func_nargs[] = {1, 2, 2, 0}; - - PyObject *pyargcount; - int i, argcount; - + char *idname= NULL; + int i; + + static struct BPY_class_attr_check pyop_class_attr_values[]= { + {PYOP_ATTR_IDNAME, 's', 0, 0}, + {PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL}, + {PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL}, + {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK}, + {"exec", 'f', 1, BPY_CLASS_ATTR_OPTIONAL}, + {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {NULL, 0, 0, 0} + }; // in python would be... //PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator"); - optype = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator"); - Py_DECREF(optype); + base_class = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator"); + Py_DECREF(base_class); - - if (!PyObject_IsSubclass(value, optype)) { - PyErr_SetString( PyExc_AttributeError, "expected Operator subclass of bpy.types.Operator"); - return NULL; + if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) { + return NULL; /* BPY_class_validate sets the error */ } - + /* class name is used for operator ID - this can be changed later if we want */ - item = PyObject_GetAttrString(value, PYOP_ATTR_IDNAME); + item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); Py_DECREF(item); idname = _PyUnicode_AsString(item); - if (WM_operatortype_find(idname)) { PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname); return NULL; } - /* Operator user readible name */ - item = PyObject_GetAttrString(value, PYOP_ATTR_UINAME); - if (item) { - Py_DECREF(item); - name = _PyUnicode_AsString(item); - } - if (name == NULL) { - name = idname; - PyErr_Clear(); - } - - /* use py docstring for description, should always be None or a string */ - item = PyObject_GetAttrString(value, PYOP_ATTR_DESCRIPTION); - Py_DECREF(item); - - if (PyUnicode_Check(item)) { - description = _PyUnicode_AsString(item); - } - else { - description = ""; - } - - /* Check known functions and argument lengths */ - for (i=0; pyop_func_names[i]; i++) { - - item=PyObject_GetAttrString(value, pyop_func_names[i]); - if (item) { - Py_DECREF(item); - - /* check its callable */ - if (!PyFunction_Check(item)) { - PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() is not a function", idname, pyop_func_names[i]); - return NULL; - } - /* check the number of args is correct */ - /* MyClass.exec.func_code.co_argcount */ - - pyargcount = PyObject_GetAttrString(PyFunction_GET_CODE(item), "co_argcount"); - Py_DECREF(pyargcount); - argcount = PyLong_AsSsize_t(pyargcount); - - if (argcount != pyop_func_nargs[i]) { - PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() takes %d args, should be %d", idname, pyop_func_names[i], argcount, pyop_func_nargs[i]); - return NULL; - } - - } else { - PyErr_Clear(); - } - } - /* If we have properties set, check its a list of dicts */ - item = PyObject_GetAttrString(value, PYOP_ATTR_PROP); + item= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP); if (item) { Py_DECREF(item); - - if (!PyList_Check(item)) { - PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.properties must be a list", idname); - return NULL; - } - for(i=0; i<PyList_Size(item); i++) { PyObject *py_args = PyList_GET_ITEM(item, i); PyObject *py_func_ptr, *py_kw; /* place holders */ @@ -477,24 +430,18 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *value) PyErr_Clear(); } - pyot= MEM_callocN(sizeof(PyOperatorType), "PyOperatorType"); - - strncpy(pyot->idname, idname, sizeof(pyot->idname)); - strncpy(pyot->name, name, sizeof(pyot->name)); - strncpy(pyot->description, description, sizeof(pyot->description)); - pyot->py_class= value; - Py_INCREF(value); - - WM_operatortype_append_ptr(PYTHON_OT_wrapper, pyot); + Py_INCREF(py_class); + WM_operatortype_append_ptr(PYTHON_OT_wrapper, py_class); Py_RETURN_NONE; } PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value) { + PyObject *py_class; char *idname= NULL; wmOperatorType *ot; - PyOperatorType *pyot; + if (PyUnicode_Check(value)) idname = _PyUnicode_AsString(value); @@ -514,13 +461,12 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value) return NULL; } - if (!(pyot= (PyOperatorType *)ot->pyop_data)) { + if (!(py_class= (PyObject *)ot->pyop_data)) { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" was not created by python", idname); return NULL; } - Py_XDECREF(pyot->py_class); - MEM_freeN(pyot); + Py_XDECREF(py_class); WM_operatortype_remove(idname); diff --git a/source/blender/python/intern/bpy_opwrapper.h b/source/blender/python/intern/bpy_operator_wrap.h index 04120a81517..2929d57ab82 100644 --- a/source/blender/python/intern/bpy_opwrapper.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -22,8 +22,8 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#ifndef BPY_OPWRAPPER_H -#define BPY_OPWRAPPER_H +#ifndef BPY_OPERATOR_WRAP_H +#define BPY_OPERATOR_WRAP_H #include <Python.h> diff --git a/source/blender/python/intern/bpy_panel_wrap.h b/source/blender/python/intern/bpy_panel_wrap.h new file mode 100644 index 00000000000..42b24703d00 --- /dev/null +++ b/source/blender/python/intern/bpy_panel_wrap.h @@ -0,0 +1,36 @@ + +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BPY_PANEL_WRAP_H +#define BPY_PANEL_WRAP_H + +#include <Python.h> + +/* these are used for operator methods, used by bpy_operator.c */ + +PyObject *PyPanel_wrap_add(PyObject *self, PyObject *args); +PyObject *PyPanel_wrap_remove(PyObject *self, PyObject *args); + +#endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 23eed552a2a..20ca134c67e 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -128,20 +128,9 @@ static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) { const EnumPropertyItem *item; int totitem, i; - - DynStr *dynstr= BLI_dynstr_new(); - char *cstring; - - RNA_property_enum_items(ptr, prop, &item, &totitem); - - for (i=0; i<totitem; i++) { - - BLI_dynstr_appendf(dynstr, i?", '%s'":"'%s'", item[i].identifier); - } - cstring = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - return cstring; + RNA_property_enum_items(ptr, prop, &item, &totitem); + return BPy_enum_as_string(item); } PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c index 7b3b4c01c55..608086843ba 100644 --- a/source/blender/python/intern/bpy_ui.c +++ b/source/blender/python/intern/bpy_ui.c @@ -27,6 +27,8 @@ #include "bpy_rna.h" /* for rna buttons */ #include "bpy_operator.h" /* for setting button operator properties */ #include "bpy_compat.h" +#include "bpy_panel_wrap.h" /* for setting button operator properties */ + #include "WM_types.h" /* for WM_OP_INVOKE_DEFAULT & friends */ #include "BLI_dynstr.h" @@ -423,6 +425,10 @@ static struct PyMethodDef ui_methods[] = { {"getScreenPtr", (PyCFunction)Method_getScreenPtr, METH_NOARGS, ""}, {"getSpacePtr", (PyCFunction)Method_getSpacePtr, METH_NOARGS, ""}, {"getWindowPtr", (PyCFunction)Method_getWindowPtr, METH_NOARGS, ""}, + + /* Adding panels should be moved, at the moment there is no obvious place as there is with operators */ + {"addPanel", (PyCFunction)PyPanel_wrap_add, METH_VARARGS, ""}, + {"removePanel", (PyCFunction)PyPanel_wrap_remove, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} }; diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 7979ca9cd37..347b914a030 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -26,7 +26,6 @@ #include "bpy_util.h" #include "BLI_dynstr.h" #include "MEM_guardedalloc.h" -#include "bpy_compat.h" PyObject *BPY_flag_to_list(struct BPY_flag_def *flagdef, int flag) { @@ -241,3 +240,91 @@ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */ return item; } + + +int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs) +{ + PyObject *item; + PyObject *py_arg_count; + int i, arg_count; + + if (base_class) { + if (!PyObject_IsSubclass(class, base_class)) { + PyObject *name= PyObject_GetAttrString(base_class, "__name__"); + PyErr_Format( PyExc_AttributeError, "expected %s subclass of class \"%s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>"); + Py_XDECREF(name); + return -1; + } + } + + for(i= 0;class_attrs->name; class_attrs++, i++) { + item = PyObject_GetAttrString(class, class_attrs->name); + + if (py_class_attrs) + py_class_attrs[i]= item; + + if (item==NULL) { + if ((class_attrs->flag & BPY_CLASS_ATTR_OPTIONAL)==0) { + PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, class_attrs->name); + return -1; + } + + PyErr_Clear(); + } + else { + Py_DECREF(item); /* no need to keep a ref, the class owns it */ + + if((item==Py_None) && (class_attrs->flag & BPY_CLASS_ATTR_NONE_OK)) { + /* dont do anything, this is ok, dont bother checking other types */ + } + else { + switch(class_attrs->type) { + case 's': + if (PyUnicode_Check(item)==0) { + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a string", class_type, class_attrs->name); + return -1; + } + break; + case 'l': + if (PyList_Check(item)==0) { + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a list", class_type, class_attrs->name); + return -1; + } + break; + case 'f': + if (PyFunction_Check(item)==0) { + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a function", class_type, class_attrs->name); + return -1; + } + if (class_attrs->arg_count >= 0) { /* -1 if we dont care*/ + py_arg_count = PyObject_GetAttrString(PyFunction_GET_CODE(item), "co_argcount"); + arg_count = PyLong_AsSsize_t(py_arg_count); + Py_DECREF(py_arg_count); + + if (arg_count != class_attrs->arg_count) { + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, class_attrs->name, class_attrs->arg_count); + return -1; + } + } + break; + } + } + } + } + return 0; +} + +char *BPy_enum_as_string(EnumPropertyItem *item) +{ + DynStr *dynstr= BLI_dynstr_new(); + EnumPropertyItem *e; + char *cstring; + + for (e= item; item->identifier; item++) { + BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier); + } + + cstring = BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + return cstring; +} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 51e13f98a35..e2bea331b0e 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -28,6 +28,9 @@ #define BPY_UTIL_H #include "bpy_compat.h" +#include "RNA_types.h" /* for EnumPropertyItem only */ + +struct EnumPropertyItem; /* for internal use only, so python can interchange a sequence of strings with flags */ typedef struct BPY_flag_def { @@ -46,4 +49,22 @@ void BPY_getFileAndNum(char **filename, int *lineno); /* own python like utility function */ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); + + +/* Class type checking, use for checking classes can be added as operators, panels etc */ +typedef struct BPY_class_attr_check { + const char *name; /* name of the class attribute */ + char type; /* 's' = string, 'f' = function, 'l' = list, (add as needed) */ + int arg_count; /* only for function types, -1 for undefined, includes self arg */ + int flag; /* other options */ +} BPY_class_attr_check; + +/* BPY_class_attr_check, flag */ +#define BPY_CLASS_ATTR_OPTIONAL 1 +#define BPY_CLASS_ATTR_NONE_OK 2 + +int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs); + +char *BPy_enum_as_string(struct EnumPropertyItem *item); + #endif |