diff --git a/release/scripts/modules/bpy_ops.py b/release/scripts/modules/bpy_ops.py index 542f9aabc7e..fbb4a8b537d 100644 --- a/release/scripts/modules/bpy_ops.py +++ b/release/scripts/modules/bpy_ops.py @@ -113,19 +113,36 @@ class bpy_ops_submodule_op(object): def __call__(self, *args, **kw): # Get the operator from blender - if len(args) > 1: - raise ValueError("only one argument for the execution context is supported ") + if len(args) > 2: + raise ValueError("only 1 or 2 arguments for the execution context is supported") + + C_dict = None if args: + + C_exec = 'EXEC_DEFAULT' + + if len(args) == 2: + C_exec = args[0] + C_dict = args[1] + else: + if type(args[0]) != str: + C_dict= args[0] + else: + C_exec= args[0] + try: - context = context_dict[args[0]] + context = context_dict[C_exec] except: raise ValueError("Expected a single context argument in: " + str(list(context_dict.keys()))) - return op_call(self.idname(), kw, context) + if len(args) == 2: + C_dict= args[1] + + return op_call(self.idname() , C_dict, kw, context) else: - return op_call(self.idname(), kw) + return op_call(self.idname(), C_dict, kw) def get_rna(self): ''' diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 09e13c2930e..feba39ee11d 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -124,6 +124,9 @@ void CTX_store_free_list(ListBase *contexts); int CTX_py_init_get(bContext *C); void CTX_py_init_set(bContext *C, int value); +void *CTX_py_dict_get(bContext *C); +void CTX_py_dict_set(bContext *C, void *value); + /* Window Manager Context */ struct wmWindowManager *CTX_wm_manager(const bContext *C); diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index d5cc31d918a..7f2872c0797 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -71,6 +71,7 @@ struct bContext { int recursion; int py_init; /* true if python is initialized */ + void *py_context; } data; /* data evaluation */ @@ -175,6 +176,15 @@ void CTX_py_init_set(bContext *C, int value) C->data.py_init= value; } +void *CTX_py_dict_get(bContext *C) +{ + return C->data.py_context; +} +void CTX_py_dict_set(bContext *C, void *value) +{ + C->data.py_context= value; +} + /* window manager context */ wmWindowManager *CTX_wm_manager(const bContext *C) @@ -401,6 +411,10 @@ static int ctx_data_get(bContext *C, const char *member, bContextDataResult *res memset(result, 0, sizeof(bContextDataResult)); + if(CTX_py_dict_get(C)) { + return bpy_context_get(C, member, result); + } + /* we check recursion to ensure that we do not get infinite * loops requesting data from ourselfs in a context callback */ if(!done && recursion < 1 && C->wm.store) { diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 1f1caeaa9b5..995be6d5023 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -757,12 +757,12 @@ static void rna_def_curve(BlenderRNA *brna) prop= RNA_def_property(srna, "render_resolution_u", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "resolu_ren"); - RNA_def_property_ui_range(prop, 1, 1024, 1, 0); + RNA_def_property_ui_range(prop, 0, 1024, 1, 0); RNA_def_property_ui_text(prop, "Render Resolution U", "Surface resolution in U direction used while rendering. Zero skips this property."); prop= RNA_def_property(srna, "render_resolution_v", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "resolv_ren"); - RNA_def_property_ui_range(prop, 1, 1024, 1, 0); + RNA_def_property_ui_range(prop, 0, 1024, 1, 0); RNA_def_property_ui_text(prop, "Render Resolution V", "Surface resolution in V direction used while rendering. Zero skips this property."); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 53c0d591437..dc7f6947f38 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -63,6 +63,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_text.h" +#include "BKE_context.h" #include "BPY_extern.h" @@ -948,3 +949,57 @@ int BPY_button_eval(bContext *C, char *expr, double *value) return error_ret; } + + +int bpy_context_get(bContext *C, const char *member, bContextDataResult *result) +{ + PyObject *pyctx= (PyObject *)CTX_py_dict_get(C); + PyObject *item= PyDict_GetItemString(pyctx, member); + PointerRNA *ptr= NULL; + int done= 0; + + if(item==NULL) { + /* pass */ + } + else if(item==Py_None) { + /* pass */ + } + else if(BPy_StructRNA_Check(item)) { + ptr= &(((BPy_StructRNA *)item)->ptr); + + //result->ptr= ((BPy_StructRNA *)item)->ptr; + CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data); + done= 1; + } + else if (PyList_Check(item)) { + int len= PyList_Size(item); + int i; + for(i = 0; i < len; i++) { + PyObject *list_item = PyList_GET_ITEM(item, i); // XXX check type + + if(BPy_StructRNA_Check(list_item)) { + /* + CollectionPointerLink *link= MEM_callocN(sizeof(CollectionPointerLink), "bpy_context_get"); + link->ptr= ((BPy_StructRNA *)item)->ptr; + BLI_addtail(&result->list, link); + */ + ptr= &(((BPy_StructRNA *)list_item)->ptr); + CTX_data_list_add(result, ptr->id.data, ptr->type, ptr->data); + } + else { + printf("List item not a valid type\n"); + } + + } + + done= 1; + } + + if(done==0) { + if (item) printf("Context '%s' not found\n", member); + else printf("Context '%s' not a valid type\n", member); + } + + return done; +} + diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 87752ca9c58..1ae0a40ce16 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -48,6 +48,8 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) char *opname; PyObject *kw= NULL; /* optional args */ + PyObject *context_dict= NULL; /* optional args */ + PyObject *context_dict_back; /* note that context is an int, python does the conversion in this case */ int context= WM_OP_EXEC_DEFAULT; @@ -55,7 +57,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) // XXX Todo, work out a better solution for passing on context, could make a tuple from self and pack the name and Context into it... bContext *C = BPy_GetContext(); - if (!PyArg_ParseTuple(args, "s|O!i:bpy.__ops__.call", &opname, &PyDict_Type, &kw, &context)) + 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); @@ -65,61 +67,74 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) return NULL; } + if(!PyDict_Check(context_dict)) + context_dict= NULL; + + context_dict_back= CTX_py_dict_get(C); + + CTX_py_dict_set(C, (void *)context_dict); + Py_XINCREF(context_dict); /* so we done loose it */ + if(WM_operator_poll((bContext*)C, ot) == FALSE) { PyErr_SetString( PyExc_SystemError, "bpy.__ops__.call: operator poll() function failed, context is incorrect"); - return NULL; + error_val= -1; } + else { + /* WM_operator_properties_create(&ptr, opname); */ + /* Save another lookup */ + RNA_pointer_create(NULL, ot->srna, NULL, &ptr); - /* WM_operator_properties_create(&ptr, opname); */ - /* Save another lookup */ - RNA_pointer_create(NULL, ot->srna, NULL, &ptr); + if(kw && PyDict_Size(kw)) + error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); + + + if (error_val==0) { + ReportList *reports; + + reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); + BKE_reports_init(reports, RPT_STORE); + + WM_operator_call_py(C, ot, context, &ptr, reports); + + if(BPy_reports_to_error(reports)) + error_val = -1; + + /* operator output is nice to have in the terminal/console too */ + if(reports->list.first) { + char *report_str= BKE_reports_string(reports, 0); /* all reports */ - if(kw && PyDict_Size(kw)) - error_val= pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: "); - + if(report_str) { + PySys_WriteStdout("%s\n", report_str); + MEM_freeN(report_str); + } + } - if (error_val==0) { - ReportList *reports; - - reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList"); - BKE_reports_init(reports, RPT_STORE); - - WM_operator_call_py(C, ot, context, &ptr, reports); - - if(BPy_reports_to_error(reports)) - error_val = -1; - - /* operator output is nice to have in the terminal/console too */ - if(reports->list.first) { - char *report_str= BKE_reports_string(reports, 0); /* all reports */ - - if(report_str) { - PySys_WriteStdout("%s\n", report_str); - MEM_freeN(report_str); + BKE_reports_clear(reports); + if ((reports->flag & RPT_FREE) == 0) + { + MEM_freeN(reports); } } - BKE_reports_clear(reports); - if ((reports->flag & RPT_FREE) == 0) - { - MEM_freeN(reports); - } - } - - WM_operator_properties_free(&ptr); + WM_operator_properties_free(&ptr); #if 0 - /* if there is some way to know an operator takes args we should use this */ - { - /* no props */ - if (kw != NULL) { - PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname); - return NULL; - } + /* if there is some way to know an operator takes args we should use this */ + { + /* no props */ + if (kw != NULL) { + PyErr_Format(PyExc_AttributeError, "Operator \"%s\" does not take any args", opname); + return NULL; + } - WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); - } + WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); + } #endif + } + + /* restore with original context dict, probably NULL but need this for nested operator calls */ + Py_XDECREF(context_dict); + CTX_py_dict_set(C, (void *)context_dict_back); if (error_val==-1) { return NULL;