Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Poirier <theeth@yahoo.com>2009-12-05 22:27:26 +0300
committerMartin Poirier <theeth@yahoo.com>2009-12-05 22:27:26 +0300
commitbcd1ab54cd1ebeda433f1c1999f5a9807c808e8e (patch)
tree54223ea8ed19ab991216cf5241f86493e77ba8ae
parent65edb7341f999f576e98ca70b15a46985a6ed9df (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.
-rw-r--r--release/scripts/modules/bpy/ops.py4
-rw-r--r--release/scripts/modules/bpy_types.py7
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_wm.c52
-rw-r--r--source/blender/python/intern/bpy_operator.c6
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c184
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.h2
-rw-r--r--source/blender/windowmanager/WM_api.h1
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c21
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c1
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", &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;
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;}