Revision: 19314
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19314
Author:   campbellbarton
Date:     2009-03-16 16:54:43 +0100 (Mon, 16 Mar 2009)

Log Message:
-----------
2.5 PyAPI
Support for subclassing blenders operator, to be registered as a new operator.

Still need to... 
* add constants like Operator.FINISHED
* wrap context (with rna?)
* poll() cant work right now because there is no way to access the operatorType 
that holds the python class.
* ?\239?\187?\191Only float, int and bool properties can be added so far.

working example operator.
http://wiki.blender.org/index.php/BlenderDev/Blender2.5/WinterCamp/TechnicalDesign#Operator_Example_Code

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.h
    
branches/blender2.5/blender/source/blender/windowmanager/intern/wm_event_system.c

Modified: 
branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c    
2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_interface.c    
2009-03-16 15:54:43 UTC (rev 19314)
@@ -57,6 +57,22 @@
        PyDict_SetItemString( dict, "__bpy_context__", item );
        Py_DECREF(item);
        
+       
+       // XXX - put somewhere more logical
+       {
+               PyMethodDef *ml;
+               static PyMethodDef bpy_prop_meths[] = {
+                       {"FloatProperty", BPy_FloatProperty, 
METH_VARARGS|METH_KEYWORDS, ""},
+                       {"IntProperty", BPy_IntProperty, 
METH_VARARGS|METH_KEYWORDS, ""},
+                       {"BoolProperty", BPy_BoolProperty, 
METH_VARARGS|METH_KEYWORDS, ""},
+                       {NULL, NULL, 0, NULL}
+               };
+               
+               for(ml = &bpy_prop_meths; ml->ml_name; ml++) {
+                       PyDict_SetItemString( dict, ml->ml_name, 
PyCFunction_New(ml, NULL));
+               }
+       }
+       
        return dict;
 }
 

Modified: 
branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c     
2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_operator.c     
2009-03-16 15:54:43 UTC (rev 19314)
@@ -111,7 +111,7 @@
 static struct PyMethodDef pyop_base_methods[] = {
        {"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""},
        {"add", (PyCFunction)PYOP_wrap_add, METH_VARARGS, ""},
-       {"remove", (PyCFunction)PYOP_wrap_remove, METH_VARARGS, ""},
+       {"remove", (PyCFunction)PYOP_wrap_remove, METH_O, ""},
        {NULL, NULL, 0, NULL}
 };
 

Modified: 
branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c    
2009-03-16 14:52:30 UTC (rev 19313)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_opwrapper.c    
2009-03-16 15:54:43 UTC (rev 19314)
@@ -45,39 +45,9 @@
        char idname[OP_MAX_TYPENAME];
        char name[OP_MAX_TYPENAME];
        char description[OP_MAX_TYPENAME]; // XXX should be longer?
-       PyObject *py_invoke;
-       PyObject *py_exec;
+       PyObject *py_class;
 } PyOperatorType;
 
-static PyObject *pyop_kwargs_from_operator(wmOperator *op)
-{
-       PyObject *dict = PyDict_New();
-       PyObject *item;
-       PropertyRNA *prop, *iterprop;
-       CollectionPropertyIterator iter;
-       const char *arg_name;
-
-       iterprop= RNA_struct_iterator_property(op->ptr);
-       RNA_property_collection_begin(op->ptr, iterprop, &iter);
-
-       for(; iter.valid; RNA_property_collection_next(&iter)) {
-               prop= iter.ptr.data;
-
-               arg_name= RNA_property_identifier(&iter.ptr, prop);
-
-               if (strcmp(arg_name, "rna_type")==0) continue;
-
-               item = pyrna_prop_to_py(op->ptr, prop);
-               PyDict_SetItemString(dict, arg_name, item);
-               Py_DECREF(item);
-       }
-
-       RNA_property_collection_end(&iter);
-
-       return dict;
-}
-
-
 static PyObject *pyop_dict_from_event(wmEvent *event)
 {
        PyObject *dict= PyDict_New();
@@ -191,33 +161,6 @@
        {NULL, 0}
 };
 
-/* exec only - no user input */
-static int PYTHON_OT_exec(bContext *C, wmOperator *op)
-{
-       PyOperatorType *pyot = op->type->pyop_data;
-       PyObject *args= PyTuple_New(0);
-       PyObject *kw= pyop_kwargs_from_operator(op);
-       PyObject *ret;
-       int ret_flag;
-
-       ret = PyObject_Call(pyot->py_exec, args, kw);
-
-       if (ret == NULL) {
-               pyop_error_report(op->reports);
-       }
-       else {
-               if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
-                        /* the returned value could not be converted into a 
flag */
-                       pyop_error_report(op->reports);
-               }
-       }
-
-       Py_DECREF(args);
-       Py_DECREF(kw);
-
-       return ret_flag;
-}
-
 /* This invoke function can take events and
  *
  * It is up to the pyot->py_invoke() python func to run pyot->py_exec()
@@ -233,26 +176,93 @@
  *     op_exec(**prop_defs)
  *
  * when there is no invoke function, C calls exec and sets the props.
+ * python class instance is stored in op->customdata so exec() can access
  */
-static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
+
+
+#define PYOP_EXEC 1
+#define PYOP_INVOKE 2
+#define PYOP_POLL 3
+       
+static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent 
*event)
 {
        PyOperatorType *pyot = op->type->pyop_data;
-       PyObject *args= PyTuple_New(2);
-       PyObject *ret;
-       int ret_flag;
+       PyObject *args;
+       PyObject *ret= NULL, *py_class_instance, *item;
+       int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
+       
+       args = PyTuple_New(1);
+       PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(pyot->py_class, 
"__rna__")); // need to use an rna instance as the first arg
+       py_class_instance = PyObject_Call(pyot->py_class, args, NULL);
+       Py_DECREF(args);
+       
+       if (py_class_instance) { /* Initializing the class worked, now run its 
invoke function */
+               
+               
+               /* Assign instance attributes from operator properties */
+               {
+                       PropertyRNA *prop, *iterprop;
+                       CollectionPropertyIterator iter;
+                       const char *arg_name;
 
-       PyTuple_SET_ITEM(args, 0, pyop_dict_from_event(event));
-       PyTuple_SET_ITEM(args, 1, pyop_kwargs_from_operator(op));
+                       iterprop= RNA_struct_iterator_property(op->ptr);
+                       RNA_property_collection_begin(op->ptr, iterprop, &iter);
 
-       ret = PyObject_Call(pyot->py_invoke, args, NULL);
+                       for(; iter.valid; RNA_property_collection_next(&iter)) {
+                               prop= iter.ptr.data;
+                               arg_name= RNA_property_identifier(&iter.ptr, 
prop);
 
+                               if (strcmp(arg_name, "rna_type")==0) continue;
+
+                               item = pyrna_prop_to_py(op->ptr, prop);
+                               PyObject_SetAttrString(py_class_instance, 
arg_name, item);
+                               Py_DECREF(item);
+                       }
+
+                       RNA_property_collection_end(&iter);
+               }
+               
+               
+               if (mode==PYOP_INVOKE) {
+                       item= PyObject_GetAttrString(pyot->py_class, "invoke");
+                       args = PyTuple_New(2);
+                       PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event));
+               }
+               else if (mode==PYOP_EXEC) {
+                       item= PyObject_GetAttrString(pyot->py_class, "exec");
+                       args = PyTuple_New(1);
+               }
+               else if (mode==PYOP_POLL) {
+                       item= PyObject_GetAttrString(pyot->py_class, "poll");
+                       args = PyTuple_New(2);
+                       //XXX  Todo - wrap context in a useful way, None for 
now.
+                       PyTuple_SET_ITEM(args, 1, Py_None);
+               }
+               PyTuple_SET_ITEM(args, 0, py_class_instance);
+       
+               ret = PyObject_Call(item, args, NULL);
+               
+               Py_DECREF(args);
+               Py_DECREF(item);
+       }
+       
        if (ret == NULL) {
                pyop_error_report(op->reports);
        }
        else {
-               if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
+               if (mode==PYOP_POLL) {
+                       if (PyBool_Check(ret) == 0) {
+                               PyErr_SetString(PyExc_ValueError, "Python poll 
function return value ");
+                               pyop_error_report(op->reports);
+                       }
+                       else {
+                               ret_flag= ret==Py_True ? 1:0;
+                       }
+                       
+               } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == 
-1) {
                         /* the returned value could not be converted into a 
flag */
                        pyop_error_report(op->reports);
+                       
                }
                /* there is no need to copy the py keyword dict modified by
                 * pyot->py_invoke(), back to the operator props since they are 
just
@@ -261,131 +271,234 @@
                 * If we ever want to do this and use the props again,
                 * it can be done with - PYOP_props_from_dict(op->ptr, kw)
                 */
+               
+               Py_DECREF(ret);
        }
 
-       
+       return ret_flag;
+}
 
-       Py_DECREF(args); /* also decref's kw */
+static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       return PYTHON_OT_generic(PYOP_INVOKE, C, op, event);    
+}
 
-       return ret_flag;
+static int PYTHON_OT_exec(bContext *C, wmOperator *op)
+{
+       return PYTHON_OT_generic(PYOP_EXEC, C, op, NULL);
 }
 
+static int PYTHON_OT_poll(bContext *C)
+{
+       // XXX TODO - no way to get the operator type (and therefor class) from 
the poll function.
+       //return PYTHON_OT_generic(PYOP_POLL, C, NULL, NULL);
+       return 1;
+}
+
 void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
 {
        PyOperatorType *pyot = (PyOperatorType *)userdata;
+       PyObject *py_class = pyot->py_class;
 
        /* identifiers */
        ot->name= pyot->name;
        ot->idname= pyot->idname;
        ot->description= pyot->description;
 
-       /* api callbacks */
-       if (pyot->py_invoke != Py_None)
+       /* api callbacks, detailed checks dont on adding */ 
+       if (PyObject_HasAttrString(py_class, "invoke"))
                ot->invoke= PYTHON_OT_invoke;
+       if (PyObject_HasAttrString(py_class, "exec"))
+               ot->exec= PYTHON_OT_exec;
+       if (PyObject_HasAttrString(py_class, "poll"))
+               ot->poll= PYTHON_OT_poll;
        
-       ot->exec= PYTHON_OT_exec;
-
-       ot->poll= ED_operator_screenactive; /* how should this work?? */
-       /* ot->flag= OPTYPE_REGISTER; */
-       
        ot->pyop_data= userdata;
        
-       /* inspect function keyword args to get properties */
-       {
-               PropertyRNA *prop;
-
-               PyObject *var_names= 
PyObject_GetAttrString(PyFunction_GET_CODE(pyot->py_exec), "co_varnames");
-               PyObject *var_vals = PyFunction_GET_DEFAULTS(pyot->py_exec);
-               PyObject *py_val, *py_name;
+       // TODO - set properties
+       PyObject *props, *item;
+       
+       
+       if ((props=PyObject_GetAttrString(py_class, "properties"))) {           
+               PyObject *dummy_args = PyTuple_New(0);
+               
                int i;
-               char *name;
-
-               if (PyTuple_Size(var_names) != PyTuple_Size(var_vals)) {
-                       printf("All args must be keywords");
-               }
-
-               for(i=0; i<PyTuple_Size(var_names); i++) {
-                       py_name = PyTuple_GetItem(var_names, i);
-                       name = _PyUnicode_AsString(py_name);
-                       py_val = PyTuple_GetItem(var_vals, i);
-
-                       if (PyBool_Check(py_val)) {
-                               prop = RNA_def_property(ot->srna, name, 
PROP_BOOLEAN, PROP_NONE);
-                               RNA_def_property_boolean_default(prop, 
PyObject_IsTrue(py_val));
+               
+               for(i=0; i<PyList_Size(props); i++) {
+                       item = PyList_GET_ITEM(props, i);
+                       
+                       PyObject *py_func_ptr, *py_kw, *py_srna_cobject, 
*py_ret;
+                       
+                       if (PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, 
&py_func_ptr, &PyDict_Type, &py_kw)) {
+                               
+                               PyObject *(*pyfunc)(PyObject *, PyObject *, 
PyObject *);
+                               pyfunc = PyCObject_AsVoidPtr(py_func_ptr);
+                               py_srna_cobject = 
PyCObject_FromVoidPtr(ot->srna, NULL);
+                               
+                               py_ret = pyfunc(py_srna_cobject, dummy_args, 
py_kw);
+                               if (py_ret) {
+                                       Py_DECREF(py_ret);
+                               } else {
+                                       PyErr_Print();
+                                       PyErr_Clear();
+                               }
+                               Py_DECREF(py_srna_cobject);
+                               
+                       } else {
+                               /* cant return NULL from here */ // XXX a bit 
ugly
+                               PyErr_Print();
+                               PyErr_Clear();
                        }
-                       else if (PyLong_Check(py_val)) {
-                               prop = RNA_def_property(ot->srna, name, 
PROP_INT, PROP_NONE);
-                               RNA_def_property_int_default(prop, 
(int)PyLong_AsSsize_t(py_val));
-                       }
-                       else if (PyFloat_Check(py_val)) {

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to