user interface units, off by default.
[blender.git] / source / blender / python / intern / bpy_operator_wrap.c
index bf92db832afb6c3e7a58d7bb7f8c3c08e7f8eb35..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 */
-
-static PyObject *pyop_dict_from_event(wmEvent *event)
-{
-       PyObject *dict= PyDict_New();
-       PyObject *item;
-       char *cstring, ascii[2];
-
-       /* type */
-       item= PyUnicode_FromString(WM_key_event_string(event->type));
-       PyDict_SetItemString(dict, "type", item);       Py_DECREF(item);
-
-       /* val */
-       switch(event->val) {
-       case KM_ANY:
-               cstring = "ANY";
-               break;
-       case KM_RELEASE:
-               cstring = "RELEASE";
-               break;
-       case KM_PRESS:
-               cstring = "PRESS";
-               break;
-       default:
-               cstring = "UNKNOWN";
-               break;
-       }
-
-       item= PyUnicode_FromString(cstring);
-       PyDict_SetItemString(dict, "val", item);        Py_DECREF(item);
-
-       /* x, y (mouse) */
-       item= PyLong_FromLong(event->x);
-       PyDict_SetItemString(dict, "x", item);          Py_DECREF(item);
-
-       item= PyLong_FromLong(event->y);
-       PyDict_SetItemString(dict, "y", item);          Py_DECREF(item);
-
-       item= PyLong_FromLong(event->prevx);
-       PyDict_SetItemString(dict, "prevx", item);      Py_DECREF(item);
-
-       item= PyLong_FromLong(event->prevy);
-       PyDict_SetItemString(dict, "prevy", item);      Py_DECREF(item);
-
-       /* ascii */
-       ascii[0]= event->ascii;
-       ascii[1]= '\0';
-       item= PyUnicode_FromString(ascii);
-       PyDict_SetItemString(dict, "ascii", item);      Py_DECREF(item);
-
-       /* modifier keys */
-       item= PyLong_FromLong(event->shift);
-       PyDict_SetItemString(dict, "shift", item);      Py_DECREF(item);
-
-       item= PyLong_FromLong(event->ctrl);
-       PyDict_SetItemString(dict, "ctrl", item);       Py_DECREF(item);
-
-       item= PyLong_FromLong(event->alt);
-       PyDict_SetItemString(dict, "alt", item);        Py_DECREF(item);
-
-       item= PyLong_FromLong(event->oskey);
-       PyDict_SetItemString(dict, "oskey", item);      Py_DECREF(item);
-
-
-
-       /* modifier */
-#if 0
-       item= PyTuple_New(0);
-       if(event->keymodifier & KM_SHIFT) {
-               _PyTuple_Resize(&item, size+1);
-               PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("SHIFT"));
-               size++;
-       }
-       if(event->keymodifier & KM_CTRL) {
-               _PyTuple_Resize(&item, size+1);
-               PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("CTRL"));
-               size++;
-       }
-       if(event->keymodifier & KM_ALT) {
-               _PyTuple_Resize(&item, size+1);
-               PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("ALT"));
-               size++;
-       }
-       if(event->keymodifier & KM_OSKEY) {
-               _PyTuple_Resize(&item, size+1);
-               PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("OSKEY"));
-               size++;
-       }
-       PyDict_SetItemString(dict, "keymodifier", item);        Py_DECREF(item);
-#endif
-
-       return dict;
-}
-
-/* TODO - a whole traceback would be ideal */
-static void pyop_error_report(ReportList *reports)
-{
-       PyObject *exception, *v, *tb;
-       PyErr_Fetch(&exception, &v, &tb);
-       if (exception == NULL)
-               return;
-       /* Now we know v != NULL too */
-       BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(v));
-       
-       PyErr_Print();
-}
+#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},
@@ -189,10 +87,14 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
        PyObject *args;
        PyObject *ret= NULL, *py_class_instance, *item= NULL;
        int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
+       PointerRNA ptr_context;
+       PointerRNA ptr_operator;
+       PointerRNA ptr_event;
+       PyObject *py_operator;
 
-       PyGILState_STATE gilstate = PyGILState_Ensure();
-       
-       BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this.
+       PyGILState_STATE gilstate;
+
+       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
@@ -204,15 +106,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                
                /* Assign instance attributes from operator properties */
                {
-                       PropertyRNA *prop, *iterprop;
-                       CollectionPropertyIterator iter;
                        const char *arg_name;
 
-                       iterprop= RNA_struct_iterator_property(op->ptr->type);
-                       RNA_property_collection_begin(op->ptr, iterprop, &iter);
-
-                       for(; iter.valid; RNA_property_collection_next(&iter)) {
-                               prop= iter.ptr.data;
+                       RNA_STRUCT_BEGIN(op->ptr, prop) {
                                arg_name= RNA_property_identifier(prop);
 
                                if (strcmp(arg_name, "rna_type")==0) continue;
@@ -221,19 +117,33 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                                PyObject_SetAttrString(py_class_instance, arg_name, item);
                                Py_DECREF(item);
                        }
-
-                       RNA_property_collection_end(&iter);
+                       RNA_STRUCT_END;
                }
-               
+
+               /* set operator pointer RNA as instance "__operator__" attribute */
+               RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
+               py_operator= pyrna_struct_CreatePyObject(&ptr_operator);
+               PyObject_SetAttrString(py_class_instance, "__operator__", py_operator);
+               Py_DECREF(py_operator);
+
+               RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
                
                if (mode==PYOP_INVOKE) {
                        item= PyObject_GetAttrString(py_class, "invoke");
-                       args = PyTuple_New(2);
-                       PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event));
+                       args = PyTuple_New(3);
+                       
+                       RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event);
+
+                       // PyTuple_SET_ITEM "steals" object reference, it is
+                       // an object passed shouldn't be DECREF'ed
+                       PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
+                       PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event));
                }
                else if (mode==PYOP_EXEC) {
-                       item= PyObject_GetAttrString(py_class, "exec");
-                       args = PyTuple_New(1);
+                       item= PyObject_GetAttrString(py_class, "execute");
+                       args = PyTuple_New(2);
+                       
+                       PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
                }
                else if (mode==PYOP_POLL) {
                        item= PyObject_GetAttrString(py_class, "poll");
@@ -250,13 +160,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
        }
        
        if (ret == NULL) { /* covers py_class_instance failing too */
-               pyop_error_report(op->reports);
+               BPy_errors_to_report(op->reports);
        }
        else {
                if (mode==PYOP_POLL) {
                        if (PyBool_Check(ret) == 0) {
                                PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
-                               pyop_error_report(op->reports);
+                               BPy_errors_to_report(op->reports);
                        }
                        else {
                                ret_flag= ret==Py_True ? 1:0;
@@ -264,8 +174,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                        
                } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
                         /* the returned value could not be converted into a flag */
-                       pyop_error_report(op->reports);
-                       
+                       BPy_errors_to_report(op->reports);
+
+                       ret_flag = OPERATOR_CANCELLED;
                }
                /* there is no need to copy the py keyword dict modified by
                 * pyot->py_invoke(), back to the operator props since they are just
@@ -278,7 +189,36 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
                Py_DECREF(ret);
        }
 
-       PyGILState_Release(gilstate);
+#if 0 /* only for testing */
+
+       /* print operator return value */
+       if (mode != PYOP_POLL) {
+               char flag_str[100];
+               char class_name[100];
+               BPY_flag_def *flag_def = pyop_ret_flags;
+
+               strcpy(flag_str, "");
+               
+               while(flag_def->name) {
+                       if (ret_flag & flag_def->flag) {
+                               if(flag_str[1])
+                                       sprintf(flag_str, "%s | %s", flag_str, flag_def->name);
+                               else
+                                       strcpy(flag_str, flag_def->name);
+                       }
+                       flag_def++;
+               }
+
+               /* get class name */
+               item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
+               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
+
+       bpy_context_clear(C, &gilstate);
 
        return ret_flag;
 }
@@ -306,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;
@@ -322,32 +261,41 @@ 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"))
                ot->invoke= PYTHON_OT_invoke;
-       if (PyObject_HasAttrString(py_class, "exec"))
+       if (PyObject_HasAttrString(py_class, "execute"))
                ot->exec= PYTHON_OT_exec;
        if (PyObject_HasAttrString(py_class, "poll"))
                ot->poll= PYTHON_OT_poll;
        
        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);
@@ -357,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();
                                }
@@ -371,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();
        }
@@ -381,45 +332,60 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
 PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
 {      
        PyObject *base_class, *item;
+       wmOperatorType *ot;
        
        
        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},
-               {"exec",        'f', 1, BPY_CLASS_ATTR_OPTIONAL},
-               {"invoke",      'f', 2, 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! */
+
        
-       if (WM_operatortype_find(idname)) {
-               PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname);
-               return NULL;
+       /* remove if it already exists */
+       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 */
@@ -429,6 +395,7 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
                                return NULL;                            
                        }
                }
+               Py_DECREF(item);
        }
        else {
                PyErr_Clear();
@@ -460,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;
        }