X-Git-Url: https://git.blender.org/gitweb/gitweb.cgi/blender.git/blobdiff_plain/65edb7341f999f576e98ca70b15a46985a6ed9df..bcd1ab54cd1ebeda433f1c1999f5a9807c808e8e:/source/blender/python/intern/bpy_operator_wrap.c diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index ff49d381dd1..cd5b0756531 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -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", ¯o, &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;