user interface units, off by default.
[blender.git] / source / blender / python / intern / bpy_operator_wrap.c
index 60a9afda0c4c5f77bd9939a8b2032f965ecef5df..9a74bf0aee8af22e37dd943a38bcbd03e4a1e753 100644 (file)
 #include "RNA_define.h"
 
 #include "bpy_rna.h"
-#include "bpy_compat.h"
 #include "bpy_util.h"
 
 #include "../generic/bpy_internal_import.h" // our own imports
 
 #define PYOP_ATTR_PROP                 "__props__"
 #define PYOP_ATTR_UINAME               "__label__"
-#define PYOP_ATTR_IDNAME               "__name__"      /* use pythons class name */
+#define PYOP_ATTR_IDNAME               "__idname__"    /* the name given by python */
+#define PYOP_ATTR_IDNAME_BL            "__idname_bl__" /* our own name converted into blender syntax, users wont see this */
 #define PYOP_ATTR_DESCRIPTION  "__doc__"       /* use pythons docstring */
+#define PYOP_ATTR_REGISTER             "__register__"  /* True/False. if this python operator should be registered */
 
 static struct BPY_flag_def pyop_ret_flags[] = {
        {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
@@ -91,11 +92,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
        PointerRNA ptr_event;
        PyObject *py_operator;
 
-       PyGILState_STATE gilstate = PyGILState_Ensure();
+       PyGILState_STATE gilstate;
 
-       bpy_import_main_set(CTX_data_main(C));
-       
-       BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this.
+       bpy_context_set(C, &gilstate);
 
        args = PyTuple_New(1);
        PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg
@@ -190,6 +189,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                Py_DECREF(ret);
        }
 
+#if 0 /* only for testing */
+
        /* print operator return value */
        if (mode != PYOP_POLL) {
                char flag_str[100];
@@ -210,14 +211,14 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 
                /* get class name */
                item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
-               Py_DECREF(item);
                strcpy(class_name, _PyUnicode_AsString(item));
+               Py_DECREF(item);
 
                fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str);
        }
+#endif
 
-       PyGILState_Release(gilstate);
-       bpy_import_main_set(NULL);
+       bpy_context_clear(C, &gilstate);
 
        return ret_flag;
 }
@@ -245,15 +246,14 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
        PyObject *props, *item;
 
        /* identifiers */
-       item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
-       Py_DECREF(item);
+       item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL);
        ot->idname= _PyUnicode_AsString(item);
-       
+       Py_DECREF(item);
 
        item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
        if (item) {
-               Py_DECREF(item);
                ot->name= _PyUnicode_AsString(item);
+               Py_DECREF(item);
        }
        else {
                ot->name= ot->idname;
@@ -261,8 +261,8 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
        }
 
        item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
-       Py_DECREF(item);
-       ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"";
+       ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
+       Py_XDECREF(item);
        
        /* api callbacks, detailed checks dont on adding */ 
        if (PyObject_HasAttrString(py_class, "invoke"))
@@ -274,19 +274,28 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
        
        ot->pyop_data= userdata;
        
+       /* flags */
+       item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
+       if (item) {
+               ot->flag= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
+               Py_DECREF(item);
+       }
+       else {
+               ot->flag= OPTYPE_REGISTER; /* unspesified, leave on for now to help debug */
+               PyErr_Clear();
+       }
+       
        props= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP);
        
        if (props) {
                PyObject *dummy_args = PyTuple_New(0);
                int i;
-               
-               Py_DECREF(props);
 
                for(i=0; i<PyList_Size(props); i++) {
                        PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret;
                        item = PyList_GET_ITEM(props, i);
                        
-                       if (PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
+                       if (PyArg_ParseTuple(item, "O!O!:PYTHON_OT_wrapper", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
                                
                                PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *);
                                pyfunc = PyCObject_AsVoidPtr(py_func_ptr);
@@ -296,6 +305,8 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
                                if (py_ret) {
                                        Py_DECREF(py_ret);
                                } else {
+                                       fprintf(stderr, "BPy Operator \"%s\" registration error: %s item %d could not run\n", ot->idname, PYOP_ATTR_PROP, i);
+                                       PyLineSpit();
                                        PyErr_Print();
                                        PyErr_Clear();
                                }
@@ -310,6 +321,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
                        // expect a tuple with a CObject and a dict
                }
                Py_DECREF(dummy_args);
+               Py_DECREF(props);
        } else {
                PyErr_Clear();
        }
@@ -324,44 +336,56 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
        
        
        char *idname= NULL;
+       char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
        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},
-               {"execute",     'f', 2, BPY_CLASS_ATTR_OPTIONAL},
-               {"invoke",      'f', 3, BPY_CLASS_ATTR_OPTIONAL},
-               {"poll",        'f', 2, BPY_CLASS_ATTR_OPTIONAL},
+               {PYOP_ATTR_IDNAME,              's', -1, OP_MAX_TYPENAME-3,     0}, /* -3 because a.b -> A_OT_b */
+               {PYOP_ATTR_UINAME,              's', -1,-1,     BPY_CLASS_ATTR_OPTIONAL},
+               {PYOP_ATTR_PROP,                'l', -1,-1,     BPY_CLASS_ATTR_OPTIONAL},
+               {PYOP_ATTR_DESCRIPTION, 's', -1,-1,     BPY_CLASS_ATTR_NONE_OK},
+               {"execute",                             'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
+               {"invoke",                              'f', 3, -1, BPY_CLASS_ATTR_OPTIONAL},
+               {"poll",                                'f', 2, -1, 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");
        base_class = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator");
-       Py_DECREF(base_class);
 
        if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
                return NULL; /* BPY_class_validate sets the error */
        }
+       Py_DECREF(base_class);
 
        /* class name is used for operator ID - this can be changed later if we want */
        item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
+       idname =  _PyUnicode_AsString(item);
+
+
+       /* annoying conversion! */
+       WM_operator_bl_idname(idname_bl, idname);
        Py_DECREF(item);
+
+       item= PyUnicode_FromString(idname_bl);
+       PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item);
        idname =  _PyUnicode_AsString(item);
+       Py_DECREF(item);
+       /* end annoying conversion! */
+
        
        /* remove if it already exists */
-       if ((ot=WM_operatortype_find(idname))) {
-               if(ot->pyop_data)
+       if ((ot=WM_operatortype_exists(idname))) {
+               if(ot->pyop_data) {
                        Py_XDECREF((PyObject*)ot->pyop_data);
+               }
                WM_operatortype_remove(idname);
        }
        
        /* If we have properties set, check its a list of dicts */
        item= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP);
        if (item) {
-               Py_DECREF(item);
                for(i=0; i<PyList_Size(item); i++) {
                        PyObject *py_args = PyList_GET_ITEM(item, i);
                        PyObject *py_func_ptr, *py_kw; /* place holders */
@@ -371,6 +395,7 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
                                return NULL;                            
                        }
                }
+               Py_DECREF(item);
        }
        else {
                PyErr_Clear();
@@ -402,7 +427,7 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
                return NULL;
        }
 
-       if (!(ot= WM_operatortype_find(idname))) {
+       if (!(ot= WM_operatortype_exists(idname))) {
                PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname);
                return NULL;
        }