diff options
author | Martin Poirier <theeth@yahoo.com> | 2009-12-05 22:27:26 +0300 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2009-12-05 22:27:26 +0300 |
commit | bcd1ab54cd1ebeda433f1c1999f5a9807c808e8e (patch) | |
tree | 54223ea8ed19ab991216cf5241f86493e77ba8ae /source/blender/python/intern | |
parent | 65edb7341f999f576e98ca70b15a46985a6ed9df (diff) |
Support for the C Macro system in Python.
Basic definition works like a python operator but you derive from "bpy.types.Macro" instead.
Operators are added to the macro after it has been added with "bpy.ops.add_macro" through the class method "define" which takes an operator id and returns an OperatorMacroType (new RNA type) for which properties can then be defined to be passed to the operator when run.
Example: http://blenderartists.org/~theeth/bf/macro.py
Using this system, it should be easy to add an operator to the console that converts selected lines into a macro or even a more generic record macro system.
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r-- | source/blender/python/intern/bpy_operator.c | 6 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator_wrap.c | 184 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator_wrap.h | 2 |
3 files changed, 191 insertions, 1 deletions
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 6ae63f2ab65..b4a2fb36a97 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -60,7 +60,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) if (!PyArg_ParseTuple(args, "sO|O!i:_bpy.ops.call", &opname, &context_dict, &PyDict_Type, &kw, &context)) return NULL; - ot= WM_operatortype_find(opname, TRUE); + ot= WM_operatortype_exists(opname); if (ot == NULL) { PyErr_Format( PyExc_SystemError, "_bpy.ops.call: operator \"%s\"could not be found", opname); @@ -245,6 +245,8 @@ PyObject *BPY_operator_module( void ) static PyMethodDef pyop_dir_meth = {"dir", (PyCFunction) pyop_dir, METH_NOARGS, NULL}; static PyMethodDef pyop_getrna_meth = {"get_rna", (PyCFunction) pyop_getrna, METH_O, NULL}; static PyMethodDef pyop_add_meth = {"add", (PyCFunction) PYOP_wrap_add, METH_O, NULL}; + static PyMethodDef pyop_add_macro_meth ={"add_macro", (PyCFunction) PYOP_wrap_add_macro, METH_O, NULL}; + static PyMethodDef pyop_macro_def_meth ={"macro_define", (PyCFunction) PYOP_wrap_macro_define, METH_VARARGS, NULL}; static PyMethodDef pyop_remove_meth = {"remove", (PyCFunction) PYOP_wrap_remove, METH_O, NULL}; PyObject *submodule = PyModule_New("_bpy.ops"); @@ -255,6 +257,8 @@ PyObject *BPY_operator_module( void ) PyModule_AddObject( submodule, "dir", PyCFunction_New(&pyop_dir_meth, NULL) ); PyModule_AddObject( submodule, "get_rna", PyCFunction_New(&pyop_getrna_meth, NULL) ); PyModule_AddObject( submodule, "add", PyCFunction_New(&pyop_add_meth, NULL) ); + PyModule_AddObject( submodule, "add_macro", PyCFunction_New(&pyop_add_macro_meth, NULL) ); + PyModule_AddObject( submodule, "macro_define",PyCFunction_New(&pyop_macro_def_meth, NULL) ); PyModule_AddObject( submodule, "remove", PyCFunction_New(&pyop_remove_meth, NULL) ); return submodule; 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; diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index 2929d57ab82..939fedd1f2b 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -29,6 +29,8 @@ /* these are used for operator methods, used by bpy_operator.c */ PyObject *PYOP_wrap_add(PyObject *self, PyObject *args); +PyObject *PYOP_wrap_add_macro(PyObject *self, PyObject *args); +PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args); PyObject *PYOP_wrap_remove(PyObject *self, PyObject *args); #endif |