awesome!<div><br><br><div class="gmail_quote">On Sat, Dec 27, 2008 at 7:52 AM, Campbell Barton <span dir="ltr"><<a href="mailto:ideasman42@gmail.com">ideasman42@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Revision: 18097<br>
<a href="http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18097" target="_blank">http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=18097</a><br>
Author: campbellbarton<br>
Date: 2008-12-27 15:52:49 +0100 (Sat, 27 Dec 2008)<br>
<br>
Log Message:<br>
-----------<br>
python operators (in bpy_opwrapper.*)<br>
This means you can define an operator in python that is called from C or Python - like any other operator.<br>
<br>
Python functions for invoke and exec can be registered with an operator name.<br>
<br>
keywords are read from the python exec() function, then used to create operator properties. The default python values are used to set the property type and defaults.<br>
<br>
def exec(size=2.0, text="blah"): ...<br>
<br>
is equivalent to...<br>
prop = RNA_def_property(ot->srna, "size", PROP_FLOAT, PROP_NONE);<br>
RNA_def_property_float_default(prop, 2.0f);<br>
<br>
prop = RNA_def_property(ot->srna, "size", PROP_STRING, PROP_NONE);<br>
RNA_def_property_string_default(prop, "blah");<br>
<br>
<br>
TODO -<br>
* make use of events<br>
* return OPERATOR_CANCELLED/OPERATOR_FINISHED.. etc<br>
* add support for array args<br>
* more testing<br>
<br>
Modified Paths:<br>
--------------<br>
branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h<br>
branches/blender2.5/blender/source/blender/makesrna/RNA_define.h<br>
branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c<br>
branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c<br>
branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c<br>
branches/blender2.5/blender/source/blender/python/intern/bpy_rna.h<br>
branches/blender2.5/blender/source/blender/windowmanager/WM_api.h<br>
branches/blender2.5/blender/source/blender/windowmanager/intern/wm_operators.c<br>
<br>
Added Paths:<br>
-----------<br>
branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c<br>
branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.h<br>
<br>
Modified: branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h<br>
===================================================================<br>
--- branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h 2008-12-27 11:44:00 UTC (rev 18096)<br>
+++ branches/blender2.5/blender/source/blender/makesdna/DNA_windowmanager_types.h 2008-12-27 14:52:49 UTC (rev 18097)<br>
@@ -137,6 +137,10 @@<br>
<br>
short flag;<br>
<br>
+ /* only used for operators defined with python<br>
+ * use to store pointers to python functions */<br>
+ void *pyop_data;<br>
+<br>
} wmOperatorType;<br>
<br>
#define OP_MAX_TYPENAME 64<br>
<br>
Modified: branches/blender2.5/blender/source/blender/makesrna/RNA_define.h<br>
===================================================================<br>
--- branches/blender2.5/blender/source/blender/makesrna/RNA_define.h 2008-12-27 11:44:00 UTC (rev 18096)<br>
+++ branches/blender2.5/blender/source/blender/makesrna/RNA_define.h 2008-12-27 14:52:49 UTC (rev 18097)<br>
@@ -47,7 +47,7 @@<br>
void RNA_def_struct_funcs(StructRNA *srna, const char *notify, const char *refine);<br>
void RNA_def_struct_identifier(StructRNA *srna, const char *identifier);<br>
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);<br>
-<br>
+void RNA_struct_free(BlenderRNA *brna, StructRNA *srna);<br>
/* Property */<br>
<br>
PropertyRNA *RNA_def_property(StructRNA *srna, const char *identifier, int type, int subtype);<br>
<br>
Modified: branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c<br>
===================================================================<br>
--- branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c 2008-12-27 11:44:00 UTC (rev 18096)<br>
+++ branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c 2008-12-27 14:52:49 UTC (rev 18097)<br>
@@ -549,6 +549,12 @@<br>
srna->description= description;<br>
}<br>
<br>
+void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)<br>
+{<br>
+ rna_freelistN(&srna->properties);<br>
+ rna_freelinkN(&brna->structs, srna);<br>
+}<br>
+<br>
/* Property Definition */<br>
<br>
PropertyRNA *RNA_def_property(StructRNA *srna, const char *identifier, int type, int subtype)<br>
<br>
Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c<br>
===================================================================<br>
--- branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c 2008-12-27 11:44:00 UTC (rev 18096)<br>
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c 2008-12-27 14:52:49 UTC (rev 18097)<br>
@@ -24,11 +24,13 @@<br>
*/<br>
<br>
#include "bpy_operator.h"<br>
+#include "bpy_opwrapper.h"<br>
#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */<br>
#include "bpy_compat.h"<br>
<br>
//#include "blendef.h"<br>
#include "BLI_dynstr.h"<br>
+<br>
#include "WM_api.h"<br>
#include "WM_types.h"<br>
<br>
@@ -40,6 +42,20 @@<br>
/* floats bigger then this are displayed as inf in the docstrings */<br>
#define MAXFLOAT_DOC 10000000<br>
<br>
+#if 0<br>
+void PyObSpit(char *name, PyObject *var) {<br>
+ fprintf(stderr, "<%s> : ", name);<br>
+ if (var==NULL) {<br>
+ fprintf(stderr, "<NIL>");<br>
+ }<br>
+ else {<br>
+ PyObject_Print(var, stderr, 0);<br>
+ }<br>
+ fprintf(stderr, "\n");<br>
+}<br>
+#endif<br>
+<br>
+<br>
static int pyop_func_compare( BPy_OperatorFunc * a, BPy_OperatorFunc * b )<br>
{<br>
return (strcmp(a->name, b->name)==0) ? 0 : -1;<br>
@@ -56,6 +72,7 @@<br>
return PyUnicode_FromFormat( "[BPy_OperatorFunc \"%s\"]", self->name);<br>
}<br>
<br>
+<br>
//---------------getattr--------------------------------------------<br>
static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname )<br>
{<br>
@@ -73,7 +90,17 @@<br>
PyList_Append(ret, item);<br>
Py_DECREF(item);<br>
}<br>
- } else {<br>
+<br>
+ item = PyUnicode_FromString("add"); PyList_Append(ret, item); Py_DECREF(item);<br>
+ item = PyUnicode_FromString("remove"); PyList_Append(ret, item); Py_DECREF(item);<br>
+ }<br>
+ else if ( strcmp( name, "add" ) == 0 ) {<br>
+ ret= PYOP_wrap_add_func();<br>
+ }<br>
+ else if ( strcmp( name, "remove" ) == 0 ) {<br>
+ ret= PYOP_wrap_remove_func();<br>
+ }<br>
+ else {<br>
ot = WM_operatortype_find(name);<br>
<br>
if (ot) {<br>
<br>
Added: branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c<br>
===================================================================<br>
--- branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c (rev 0)<br>
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c 2008-12-27 14:52:49 UTC (rev 18097)<br>
@@ -0,0 +1,252 @@<br>
+<br>
+/**<br>
+ * $Id$<br>
+ *<br>
+ * ***** BEGIN GPL LICENSE BLOCK *****<br>
+ *<br>
+ * This program is free software; you can redistribute it and/or<br>
+ * modify it under the terms of the GNU General Public License<br>
+ * as published by the Free Software Foundation; either version 2<br>
+ * of the License, or (at your option) any later version.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License<br>
+ * along with this program; if not, write to the Free Software Foundation,<br>
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.<br>
+ *<br>
+ * Contributor(s): Campbell Barton<br>
+ *<br>
+ * ***** END GPL LICENSE BLOCK *****<br>
+ */<br>
+<br>
+<br>
+#include "bpy_opwrapper.h"<br>
+#include "BLI_listbase.h"<br>
+#include "BKE_context.h"<br>
+#include "DNA_windowmanager_types.h"<br>
+#include "MEM_guardedalloc.h"<br>
+#include "WM_api.h"<br>
+#include "WM_types.h"<br>
+#include "ED_screen.h"<br>
+<br>
+#include "RNA_define.h"<br>
+<br>
+#include "bpy_rna.h"<br>
+#include "bpy_compat.h"<br>
+<br>
+typedef struct PyOperatorType {<br>
+ void *next, *prev;<br>
+ char idname[OP_MAX_TYPENAME];<br>
+ char name[OP_MAX_TYPENAME];<br>
+ PyObject *py_invoke;<br>
+ PyObject *py_exec;<br>
+} PyOperatorType;<br>
+<br>
+static void pyop_kwargs_from_operator(PyObject *dict, wmOperator *op)<br>
+{<br>
+ PyObject *item;<br>
+ PropertyRNA *prop, *iterprop;<br>
+ CollectionPropertyIterator iter;<br>
+ const char *arg_name;<br>
+<br>
+ iterprop= RNA_struct_iterator_property(op->ptr);<br>
+ RNA_property_collection_begin(op->ptr, iterprop, &iter);<br>
+<br>
+ for(; iter.valid; RNA_property_collection_next(&iter)) {<br>
+ prop= iter.ptr.data;<br>
+<br>
+ arg_name= RNA_property_identifier(&iter.ptr, prop);<br>
+<br>
+ if (strcmp(arg_name, "rna_type")==0) continue;<br>
+<br>
+ item = pyrna_prop_to_py(&iter.ptr, prop);<br>
+ PyDict_SetItemString(dict, arg_name, item);<br>
+ Py_DECREF(item);<br>
+ }<br>
+<br>
+ RNA_property_collection_end(&iter);<br>
+<br>
+}<br>
+<br>
+static int PYTHON_OT_exec(bContext *C, wmOperator *op)<br>
+{<br>
+ PyOperatorType *pyot = op->type->pyop_data;<br>
+ PyObject *ret, *args= PyTuple_New(0), *kw= PyDict_New();<br>
+<br>
+ pyop_kwargs_from_operator(kw, op);<br>
+<br>
+ ret = PyObject_Call(pyot->py_exec, args, kw);<br>
+<br>
+ Py_DECREF(args);<br>
+ Py_DECREF(kw);<br>
+<br>
+ return OPERATOR_FINISHED;<br>
+}<br>
+<br>
+static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)<br>
+{<br>
+ PyOperatorType *pyot = op->type->pyop_data;<br>
+ PyObject *ret, *args= PyTuple_New(0), *kw= PyDict_New();<br>
+<br>
+ pyop_kwargs_from_operator(kw, op);<br>
+<br>
+ ret = PyObject_Call(pyot->py_invoke, args, kw);<br>
+<br>
+ Py_DECREF(args);<br>
+ Py_DECREF(kw);<br>
+<br>
+ return OPERATOR_FINISHED;<br>
+}<br>
+<br>
+void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)<br>
+{<br>
+ PyOperatorType *pyot = (PyOperatorType *)userdata;<br>
+<br>
+ /* identifiers */<br>
+ ot->name= pyot->name;<br>
+ ot->idname= pyot->idname;<br>
+<br>
+ /* api callbacks */<br>
+ if (pyot->py_invoke != Py_None)<br>
+ ot->invoke= PYTHON_OT_invoke;<br>
+<br>
+ ot->exec= PYTHON_OT_exec;<br>
+<br>
+ ot->poll= ED_operator_screenactive; /* how should this work?? */<br>
+<br>
+ ot->pyop_data= userdata;<br>
+<br>
+ /* inspect function keyword args to get properties */<br>
+ {<br>
+ PropertyRNA *prop;<br>
+<br>
+ PyObject *var_names= PyObject_GetAttrString(PyFunction_GET_CODE(pyot->py_exec), "co_varnames");<br>
+ PyObject *var_vals = PyFunction_GET_DEFAULTS(pyot->py_exec);<br>
+ PyObject *py_val, *py_name;<br>
+ int i;<br>
+ char *name;<br>
+<br>
+ if (PyTuple_Size(var_names) != PyTuple_Size(var_vals)) {<br>
+ printf("All args must be keywords");<br>
+ }<br>
+<br>
+ for(i=0; i<PyTuple_Size(var_names); i++) {<br>
+ py_name = PyTuple_GetItem(var_names, i);<br>
+ name = _PyUnicode_AsString(py_name);<br>
+ py_val = PyTuple_GetItem(var_vals, i);<br>
+<br>
+ if (PyBool_Check(py_val)) {<br>
+ prop = RNA_def_property(ot->srna, name, PROP_BOOLEAN, PROP_NONE);<br>
+ RNA_def_property_boolean_default(prop, PyObject_IsTrue(py_val));<br>
+ }<br>
+ else if (PyLong_Check(py_val)) {<br>
+ prop = RNA_def_property(ot->srna, name, PROP_INT, PROP_NONE);<br>
+ RNA_def_property_int_default(prop, (int)PyLong_AsSsize_t(py_val));<br>
+ }<br>
+ else if (PyFloat_Check(py_val)) {<br>
+ prop = RNA_def_property(ot->srna, name, PROP_FLOAT, PROP_NONE);<br>
+ RNA_def_property_float_default(prop, (float)PyFloat_AsDouble(py_val));<br>
+ }<br>
+ else if (PyUnicode_Check(py_val)) {<br>
+ /* WARNING - holding a reference to the string from py_val is<br>
+ * not ideal since we rely on python keeping it,<br>
+ * however we're also keeping a reference to this function<br>
+ * so it should be OK!. just be careful with changes */<br>
+ prop = RNA_def_property(ot->srna, name, PROP_STRING, PROP_NONE);<br>
+ RNA_def_property_string_default(prop, _PyUnicode_AsString(py_val));<br>
+ }<br>
+ else {<br>
+ printf("error, python function arg \"%s\" was not a bool, int, float or string type\n", name);<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+}<br>
+<br>
+/* pyOperators - Operators defined IN Python */<br>
+static PyObject *pyop_add(PyObject *self, PyObject *args)<br>
+{<br>
+ PyOperatorType *pyot;<br>
+<br>
+ char *idname= NULL;<br>
+ char *name= NULL;<br>
+ PyObject *invoke= NULL;<br>
+ PyObject *exec= NULL;<br>
+<br>
+ if (!PyArg_ParseTuple(args, "ssOO", &idname, &name, &invoke, &exec))<br>
+ PyErr_SetString( PyExc_AttributeError, "expected 2 strings and 2 function objects");<br>
+ return NULL;<br>
+<br>
+ if (WM_operatortype_find(idname)) {<br>
+ PyErr_Format( PyExc_AttributeError, "First argument \"%s\" operator alredy exists with this name", idname);<br>
+ return NULL;<br>
+ }<br>
+<br>
+ if (((PyFunction_Check(invoke) || invoke==Py_None) && PyFunction_Check(exec)) == 0) {<br>
+ PyErr_SetString( PyExc_AttributeError, "the 2nd arg must be a function or None, the secons must be a function");<br>
+ return NULL;<br>
+ }<br>
+<br>
+ pyot= MEM_callocN(sizeof(PyOperatorType), "PyOperatorType");<br>
+<br>
+ strcpy(pyot->idname, idname);<br>
+ strcpy(pyot->name, name);<br>
+ pyot->py_invoke= invoke;<br>
+ pyot->py_exec= exec;<br>
+ Py_INCREF(invoke);<br>
+ Py_INCREF(exec);<br>
+<br>
+ WM_operatortype_append_ptr(PYTHON_OT_wrapper, pyot);<br>
+<br>
+ Py_RETURN_NONE;<br>
+}<br>
+<br>
+static PyObject *pyop_remove(PyObject *self, PyObject *args)<br>
+{<br>
+ char *idname= NULL;<br>
+ wmOperatorType *ot;<br>
+ PyOperatorType *pyot;<br>
+<br>
+ if (!PyArg_ParseTuple(args, "s", &idname))<br>
+ return NULL;<br>
+<br>
+ if (!(ot= WM_operatortype_find(idname))) {<br>
<br>
@@ Diff output truncated at 10240 characters. @@<br>
<br>
_______________________________________________<br>
Bf-blender-cvs mailing list<br>
<a href="mailto:Bf-blender-cvs@blender.org">Bf-blender-cvs@blender.org</a><br>
<a href="http://lists.blender.org/mailman/listinfo/bf-blender-cvs" target="_blank">http://lists.blender.org/mailman/listinfo/bf-blender-cvs</a><br>
</blockquote></div><br></div>