Support for the C Macro system in Python.
[blender.git] / source / blender / python / intern / bpy_operator_wrap.c
index ff49d381dd1440bbee26804ea8022ed2a3df6182..cd5b07565312227875fe63a1f7fe8c0f8cbe3ea5 100644 (file)
@@ -342,6 +342,80 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
        }
 }
 
+void PYTHON_OT_MACRO_wrapper(wmOperatorType *ot, void *userdata)
+{
+       PyObject *py_class = (PyObject *)userdata;
+       PyObject *item;
+
+       /* identifiers */
+       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) {
+               ot->name= _PyUnicode_AsString(item);
+               Py_DECREF(item);
+       }
+       else {
+               ot->name= ot->idname;
+               PyErr_Clear();
+       }
+
+       item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
+       ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
+       Py_XDECREF(item);
+
+       if (PyObject_HasAttrString(py_class, "poll"))
+               ot->pyop_poll= PYTHON_OT_poll;
+       if (PyObject_HasAttrString(py_class, "draw"))
+               ot->ui= PYTHON_OT_draw;
+
+       ot->pyop_data= userdata;
+
+       /* flags */
+       ot->flag= OPTYPE_MACRO; /* macro at least */
+
+       item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
+       if (item) {
+               ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
+               Py_DECREF(item);
+       }
+       else {
+               PyErr_Clear();
+       }
+       item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO);
+       if (item) {
+               ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0;
+               Py_DECREF(item);
+       }
+       else {
+               PyErr_Clear();
+       }
+
+       /* Can't use this because it returns a dict proxy
+        *
+        * item= PyObject_GetAttrString(py_class, "__dict__");
+        */
+       item= ((PyTypeObject*)py_class)->tp_dict;
+       if(item) {
+               /* only call this so pyrna_deferred_register_props gives a useful error
+                * WM_operatortype_append_macro_ptr will call RNA_def_struct_identifier
+                * later */
+               RNA_def_struct_identifier(ot->srna, ot->idname);
+
+               if(pyrna_deferred_register_props(ot->srna, item)!=0) {
+                       /* failed to register operator props */
+                       PyErr_Print();
+                       PyErr_Clear();
+
+               }
+       }
+       else {
+               PyErr_Clear();
+       }
+}
+
 
 /* pyOperators - Operators defined IN Python */
 PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
@@ -407,6 +481,116 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
        Py_RETURN_NONE;
 }
 
+/* pyOperators - Macro Operators defined IN Python */
+PyObject *PYOP_wrap_add_macro(PyObject *self, PyObject *py_class)
+{
+       PyObject *base_class, *item;
+       wmOperatorType *ot;
+
+
+       char *idname= NULL;
+       char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
+
+       static struct BPY_class_attr_check pyop_class_attr_values[]= {
+               {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_DESCRIPTION, 's', -1,-1,     BPY_CLASS_ATTR_NONE_OK},
+               {"poll",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
+               {"draw",                                'f', 2, -1, BPY_CLASS_ATTR_OPTIONAL},
+               {NULL, 0, 0, 0}
+       };
+
+       //PyObject bpy_mod= PyDict_GetItemString(PyEval_GetGlobals(), "bpy");
+       PyObject *bpy_mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
+       base_class = PyObject_GetAttrStringArgs(bpy_mod, 2, "types", "Macro");
+       Py_DECREF(bpy_mod);
+
+       if(BPY_class_validate("Macro", 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_exists(idname))) {
+               if(ot->pyop_data) {
+                       Py_XDECREF((PyObject*)ot->pyop_data);
+               }
+               WM_operatortype_remove(idname);
+       }
+
+       Py_INCREF(py_class);
+       WM_operatortype_append_macro_ptr(PYTHON_OT_MACRO_wrapper, py_class);
+
+       Py_RETURN_NONE;
+}
+
+PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args)
+{
+       wmOperatorType *ot;
+       wmOperatorTypeMacro *otmacro;
+       PyObject *macro;
+       PyObject *item;
+       PointerRNA ptr_otmacro;
+
+       char *opname;
+       char *macroname;
+
+       if (!PyArg_ParseTuple(args, "Os:_bpy.ops.macro_define", &macro, &opname))
+               return NULL;
+
+       if (WM_operatortype_exists(opname) == NULL) {
+               PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid operator id", opname);
+               return NULL;
+       }
+
+       /* identifiers */
+       item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME_BL);
+
+       if (!item) {
+               item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME);
+
+               if (!item) {
+                       PyErr_Format(PyExc_ValueError, "Macro Define: not a valid Macro class");
+               } else {
+                       macroname= _PyUnicode_AsString(item);
+                       PyErr_Format(PyExc_ValueError, "Macro Define: '%s' hasn't been registered yet", macroname);
+               }
+               return NULL;
+       }
+
+       macroname= _PyUnicode_AsString(item);
+
+       ot = WM_operatortype_exists(macroname);
+
+       if (!ot) {
+               PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid macro or hasn't been registered yet", macroname);
+               return NULL;
+       }
+
+       otmacro = WM_operatortype_macro_define(ot, opname);
+
+       RNA_pointer_create(NULL, &RNA_OperatorTypeMacro, otmacro, &ptr_otmacro);
+
+       return pyrna_struct_CreatePyObject(&ptr_otmacro);
+}
+
+
 PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
 {
        PyObject *py_class;