Python Panels WIP
authorCampbell Barton <ideasman42@gmail.com>
Wed, 1 Apr 2009 12:43:07 +0000 (12:43 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 1 Apr 2009 12:43:07 +0000 (12:43 +0000)
- Register python panels
- Added a generic class checking function BPY_class_validate() for panels/operators.
- No button drawing yet

Brecht, Added RNA_enum_value_from_id() and RNA_enum_id_from_value() to rna_access.c to do lookups between identifiers and values of EnumPropertyItem's, Not sure if these should go here.

18 files changed:
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/screen.c
source/blender/editors/include/ED_mesh.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_space.c
source/blender/python/BPY_extern.h
source/blender/python/intern/bpy_interface.c
source/blender/python/intern/bpy_operator.c
source/blender/python/intern/bpy_operator_wrap.c [moved from source/blender/python/intern/bpy_opwrapper.c with 75% similarity]
source/blender/python/intern/bpy_operator_wrap.h [moved from source/blender/python/intern/bpy_opwrapper.h with 95% similarity]
source/blender/python/intern/bpy_panel_wrap.h [new file with mode: 0644]
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_ui.c
source/blender/python/intern/bpy_util.c
source/blender/python/intern/bpy_util.h

index 4762261..9d28309 100644 (file)
@@ -41,7 +41,6 @@
 
 #include "BKE_context.h"
 #include "BKE_main.h"
-#include "BKE_report.h"
 #include "BKE_screen.h"
 
 #include <string.h>
index 483876e..2f3ca52 100644 (file)
@@ -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);
        }
        
index 53b5046..3570630 100644 (file)
@@ -43,6 +43,7 @@ struct bDeformGroup;
 struct MDeformWeight;
 struct MDeformVert;
 struct Scene;
+struct Mesh;
 struct MCol;
 struct UvVertMap;
 struct UvMapVert;
index cde4c4d..1bc8980 100644 (file)
@@ -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);
index 9cb49fc..f8c0ba1 100644 (file)
@@ -30,6 +30,8 @@
 /* Types */
 
 extern EnumPropertyItem prop_mode_items[];
+extern EnumPropertyItem space_type_items[];
+extern EnumPropertyItem region_type_items[];
 
 #endif /* RNA_ENUM_TYPES */
 
index 52b1b77..cf6072c 100644 (file)
@@ -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);
index 9508357..00cf29b 100644 (file)
 #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
index 5184e90..9950d70 100644 (file)
 
 #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.");
 }
index 4b7238a..690dc71 100644 (file)
@@ -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); */
index 94ec8de..f803136 100644 (file)
@@ -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)
index 02f4723..29ec337 100644 (file)
@@ -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"
 
@@ -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"
 #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);
 
@@ -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 (file)
index 0000000..42b2470
--- /dev/null
@@ -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
index 23eed55..20ca134 100644 (file)
@@ -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)
index 7b3b4c0..6080868 100644 (file)
@@ -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}
 };
 
index 7979ca9..347b914 100644 (file)
@@ -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;
+}
index 51e13f9..e2bea33 100644 (file)
@@ -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