diff options
-rw-r--r-- | release/scripts/modules/bpy/ops.py | 4 | ||||
-rw-r--r-- | release/scripts/modules/bpy_types.py | 7 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_wm.c | 52 | ||||
-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 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 21 | ||||
-rw-r--r-- | source/blenderplayer/bad_level_call_stubs/stubs.c | 1 |
10 files changed, 278 insertions, 1 deletions
diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py index 5b3009db2bf..c8218d6703c 100644 --- a/release/scripts/modules/bpy/ops.py +++ b/release/scripts/modules/bpy/ops.py @@ -23,6 +23,7 @@ from _bpy import ops as ops_module op_add = ops_module.add op_remove = ops_module.remove +op_add_macro = ops_module.add_macro op_dir = ops_module.dir op_call = ops_module.call op_as_string = ops_module.as_string @@ -58,6 +59,9 @@ class bpy_ops(object): def add(self, pyop): op_add(pyop) + + def add_macro(self, pyop): + op_add_macro(pyop) def remove(self, pyop): op_remove(pyop) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 565f0e4da1b..5a8d6ceedf6 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -252,6 +252,13 @@ class OrderedMeta(type): class Operator(StructRNA, metaclass=OrderedMeta): pass +class Macro(StructRNA, metaclass=OrderedMeta): + # bpy_types is imported before ops is defined + # so we have to do a local import on each run + @classmethod + def define(self, opname): + from _bpy import ops + return ops.macro_define(self, opname) class Menu(StructRNA): diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 36653f8c06e..959109f7bbb 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -323,6 +323,7 @@ extern StructRNA RNA_OperatorFileListElement; extern StructRNA RNA_OperatorMousePath; extern StructRNA RNA_OperatorProperties; extern StructRNA RNA_OperatorStrokeElement; +extern StructRNA RNA_OperatorTypeMacro; extern StructRNA RNA_OrController; extern StructRNA RNA_OutflowFluidSettings; extern StructRNA RNA_PackedFile; diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 10e27814236..35f2a31b7ef 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -309,6 +309,12 @@ static PointerRNA rna_Operator_properties_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, op->type->srna, op->properties); } +static PointerRNA rna_OperatorTypeMacro_properties_get(PointerRNA *ptr) +{ + wmOperatorTypeMacro *otmacro= (wmOperatorTypeMacro*)ptr->data; + wmOperatorType *ot = WM_operatortype_exists(otmacro->idname); + return rna_pointer_inherit_refine(ptr, ot->srna, otmacro->properties); +} static void rna_Event_ascii_get(PointerRNA *ptr, char *value) { @@ -593,6 +599,50 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_struct_idproperties_func(srna, "rna_OperatorProperties_idproperties"); } +static void rna_def_macro_operator(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "Macro", NULL); + RNA_def_struct_ui_text(srna, "Macro Operator", "Storage of a macro operator being executed, or registered after execution."); + RNA_def_struct_sdna(srna, "wmOperator"); + + prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_funcs(prop, "rna_Operator_name_get", "rna_Operator_name_length", NULL); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "OperatorProperties"); + RNA_def_property_ui_text(prop, "Properties", ""); + RNA_def_property_pointer_funcs(prop, "rna_Operator_properties_get", NULL, NULL); +} + +static void rna_def_operator_type_macro(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna= RNA_def_struct(brna, "OperatorTypeMacro", NULL); + RNA_def_struct_ui_text(srna, "OperatorTypeMacro", "Storage of a sub operator in a macro after it has been added."); + RNA_def_struct_sdna(srna, "wmOperatorTypeMacro"); + +// prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); +// RNA_def_property_clear_flag(prop, PROP_EDITABLE); +// RNA_def_property_string_sdna(prop, NULL, "idname"); +// RNA_def_property_ui_text(prop, "Name", "Name of the sub operator."); +// RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "OperatorProperties"); + RNA_def_property_ui_text(prop, "Properties", ""); + RNA_def_property_pointer_funcs(prop, "rna_OperatorTypeMacro_properties_get", NULL, NULL); +} + static void rna_def_operator_utils(BlenderRNA *brna) { StructRNA *srna; @@ -911,6 +961,8 @@ void RNA_def_wm(BlenderRNA *brna) rna_def_operator(brna); rna_def_operator_utils(brna); rna_def_operator_filelist_element(brna); + rna_def_macro_operator(brna); + rna_def_operator_type_macro(brna); rna_def_event(brna); rna_def_window(brna); rna_def_windowmanager(brna); 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 diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a270b75eea1..549ef11c14e 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -180,6 +180,7 @@ wmOperatorType *WM_operatortype_exists(const char *idname); wmOperatorType *WM_operatortype_first(void); void WM_operatortype_append (void (*opfunc)(wmOperatorType*)); void WM_operatortype_append_ptr (void (*opfunc)(wmOperatorType*, void *), void *userdata); +void WM_operatortype_append_macro_ptr (void (*opfunc)(wmOperatorType*, void *), void *userdata); int WM_operatortype_remove(const char *idname); wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9cee2140fc7..582410c4368 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -353,6 +353,27 @@ wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag) return ot; } +void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType*, void*), void *userdata) +{ + wmOperatorType *ot; + + ot= MEM_callocN(sizeof(wmOperatorType), "operatortype"); + ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties"); + + ot->exec= wm_macro_exec; + ot->invoke= wm_macro_invoke; + ot->modal= wm_macro_modal; + ot->cancel= wm_macro_cancel; + ot->poll= NULL; + + opfunc(ot, userdata); + + RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)"); + RNA_def_struct_identifier(ot->srna, ot->idname); + + BLI_addtail(&global_ops, ot); +} + wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname) { wmOperatorTypeMacro *otmacro= MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro"); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 7f9928262c3..9abd518ff6e 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -232,6 +232,7 @@ void WM_operator_properties_free(struct PointerRNA *ptr){} void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring){} void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot){} void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType*, void*), void *userdata){} +void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType*, void*), void *userdata){} void WM_operator_bl_idname(char *to, const char *from){} void WM_operator_py_idname(char *to, const char *from){} short insert_keyframe (struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag){return 0;} |