diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py index ba56fa12fe1..c6bdc21afa6 100644 --- a/release/scripts/modules/bpy/ops.py +++ b/release/scripts/modules/bpy/ops.py @@ -115,14 +115,34 @@ class bpy_ops_submodule_op(object): def _get_doc(self): return op_as_string(self.idname()) + @staticmethod + def _parse_args(args): + C_dict = None + C_exec = 'EXEC_DEFAULT' + + if len(args) == 0: + pass + elif len(args) == 1: + if type(args[0]) != str: + C_dict = args[0] + else: + C_exec = args[0] + elif len(args) == 2: + C_exec, C_dict = args + else: + raise ValueError("1 or 2 args execution context is supported") + + return C_dict, C_exec + __doc__ = property(_get_doc) def __init__(self, module, func): self.module = module self.func = func - def poll(self, context=None): - return op_poll(self.idname_py(), context) + def poll(self, *args): + C_dict, C_exec = __class__._parse_args(args) + return op_poll(self.idname_py(), C_dict, C_exec) def idname(self): # submod.foo -> SUBMOD_OT_foo @@ -135,31 +155,11 @@ class bpy_ops_submodule_op(object): def __call__(self, *args, **kw): # Get the operator from blender - if len(args) > 2: - raise ValueError("1 or 2 args 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] - - if len(args) == 2: - C_dict = args[1] - + C_dict, C_exec = __class__._parse_args(args) ret = op_call(self.idname_py(), C_dict, kw, C_exec) - else: - ret = op_call(self.idname_py(), C_dict, kw) + ret = op_call(self.idname_py(), None, kw) if 'FINISHED' in ret: import bpy diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index eee4f133043..099629b0422 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -629,7 +629,7 @@ void uiEndBlock(const bContext *C, uiBlock *block) if(but->context) CTX_store_set((bContext*)C, but->context); - if(ot == NULL || WM_operator_poll((bContext*)C, ot)==0) { + if(ot == NULL || WM_operator_poll_context((bContext*)C, ot, but->opcontext)==0) { but->flag |= UI_BUT_DISABLED; but->lock = 1; } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 5f8d604817a..e244565a6a6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -434,7 +434,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if(but->flag & UI_BUT_DISABLED) { const char *poll_msg; CTX_wm_operator_poll_msg_set(C, NULL); - WM_operator_poll(C, but->optype); + WM_operator_poll_context(C, but->optype, but->opcontext); poll_msg= CTX_wm_operator_poll_msg_get(C); if(poll_msg) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Disabled: %s", poll_msg); diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 1cf99218bf6..f3e960f87b2 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -46,12 +46,15 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) char *opname; PyObject *context_dict= NULL; /* optional args */ PyObject *context_dict_back; + char *context_str= NULL; PyObject *ret; + int context= WM_OP_EXEC_DEFAULT; + // 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:_bpy.ops.poll", &opname, &context_dict)) + if (!PyArg_ParseTuple(args, "s|Os:_bpy.ops.poll", &opname, &context_dict, &context_str)) return NULL; ot= WM_operatortype_find(opname, TRUE); @@ -61,6 +64,15 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) return NULL; } + if(context_str) { + if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) { + char *enum_str= BPy_enum_as_string(operator_context_items); + PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, expected a string enum in (%.200s)", opname, enum_str); + MEM_freeN(enum_str); + return NULL; + } + } + if(!PyDict_Check(context_dict)) context_dict= NULL; @@ -70,7 +82,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) Py_XINCREF(context_dict); /* so we done loose it */ /* main purpose of thsi function */ - ret= WM_operator_poll((bContext*)C, ot) ? Py_True : Py_False; + ret= WM_operator_poll_context((bContext*)C, ot, context) ? Py_True : Py_False; /* restore with original context dict, probably NULL but need this for nested operator calls */ Py_XDECREF(context_dict); @@ -126,7 +138,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) 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) { + if(WM_operator_poll_context((bContext*)C, ot, context) == FALSE) { const char *msg= CTX_wm_operator_poll_msg_get(C); PyErr_Format( PyExc_SystemError, "Operator bpy.ops.%.200s.poll() %s", opname, msg ? msg : "failed, context is incorrect"); CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 2a36e91ac66..7d4690ac7e1 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -218,6 +218,7 @@ struct wmOperatorTypeMacro *WM_operatortype_macro_define(struct wmOperatorType * int WM_operator_poll (struct bContext *C, struct wmOperatorType *ot); +int WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, int context); int WM_operator_call (struct bContext *C, struct wmOperator *op); int WM_operator_repeat (struct bContext *C, struct wmOperator *op); int WM_operator_name_call (struct bContext *C, const char *opstring, int context, struct PointerRNA *properties); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index ed1caa5fafe..910a528d419 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -72,6 +72,8 @@ #include "wm_event_types.h" #include "wm_draw.h" +static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only); + /* ************ event management ************** */ void wm_event_add(wmWindow *win, wmEvent *event_to_add) @@ -379,6 +381,12 @@ int WM_operator_poll(bContext *C, wmOperatorType *ot) return 1; } +/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */ +int WM_operator_poll_context(bContext *C, wmOperatorType *ot, int context) +{ + return wm_operator_call_internal(C, ot, NULL, NULL, context, TRUE); +} + static void wm_operator_print(wmOperator *op) { char *buf = WM_operator_pystring(NULL, op->type, op->ptr, 1); @@ -603,11 +611,15 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event) } } -int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports) +int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only) { wmWindowManager *wm= CTX_wm_manager(C); int retval= OPERATOR_PASS_THROUGH; + /* this is done because complicated setup is done to call this function that is better not duplicated */ + if(poll_only) + return WM_operator_poll(C, ot); + if(WM_operator_poll(C, ot)) { wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */ @@ -693,7 +705,7 @@ int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerR * this is for python to access since its done the operator lookup * * invokes operator in context */ -static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int context, PointerRNA *properties, ReportList *reports) +static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only) { wmWindow *window= CTX_wm_window(C); wmEvent *event; @@ -758,7 +770,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int contex CTX_wm_region_set(C, ar1); } - retval= wm_operator_invoke(C, ot, event, properties, reports); + retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); /* set region back */ CTX_wm_region_set(C, ar); @@ -772,7 +784,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int contex ARegion *ar= CTX_wm_region(C); CTX_wm_region_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports); + retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); CTX_wm_region_set(C, ar); return retval; @@ -786,7 +798,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int contex CTX_wm_region_set(C, NULL); CTX_wm_area_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports); + retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); CTX_wm_region_set(C, ar); CTX_wm_area_set(C, area); @@ -794,7 +806,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, int contex } case WM_OP_EXEC_DEFAULT: case WM_OP_INVOKE_DEFAULT: - return wm_operator_invoke(C, ot, event, properties, reports); + return wm_operator_invoke(C, ot, event, properties, reports, poll_only); } } @@ -807,7 +819,7 @@ int WM_operator_name_call(bContext *C, const char *opstring, int context, Pointe { wmOperatorType *ot= WM_operatortype_find(opstring, 0); if(ot) - return wm_operator_call_internal(C, ot, context, properties, NULL); + return wm_operator_call_internal(C, ot, properties, NULL, context, FALSE); return 0; } @@ -839,7 +851,7 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name); #endif - retval= wm_operator_call_internal(C, ot, context, properties, reports); + retval= wm_operator_call_internal(C, ot, properties, reports, context, FALSE); /* keep the reports around if needed later */ if ( (retval & OPERATOR_RUNNING_MODAL) || @@ -1168,7 +1180,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0); if(ot) - retval= wm_operator_invoke(C, ot, event, properties, NULL); + retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE); } /* Finished and pass through flag as handled */ @@ -1421,7 +1433,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) if(drop->poll(C, drag, event)) { drop->copy(drag, drop); - wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL); + wm_operator_invoke(C, drop->ot, event, drop->ptr, NULL, FALSE); action |= WM_HANDLER_BREAK; } }