2.5: Python operators now have a working poll() function,
solved by wrapping all polling in WM_operator_poll and adding a special callback for python.
This commit is contained in:
		@@ -250,7 +250,6 @@ class EXPORT_OT_ply(bpy.types.Operator):
 | 
			
		||||
	]
 | 
			
		||||
	
 | 
			
		||||
	def poll(self, context):
 | 
			
		||||
		print("Poll")
 | 
			
		||||
		return context.active_object != None
 | 
			
		||||
	
 | 
			
		||||
	def execute(self, context):
 | 
			
		||||
 
 | 
			
		||||
@@ -597,7 +597,7 @@ void uiEndBlock(const bContext *C, uiBlock *block)
 | 
			
		||||
			if(but->context)
 | 
			
		||||
				CTX_store_set((bContext*)C, but->context);
 | 
			
		||||
 | 
			
		||||
			if(ot==NULL || (ot->poll && ot->poll((bContext *)C)==0)) {
 | 
			
		||||
			if(ot == NULL || WM_operator_poll((bContext*)C, ot)==0) {
 | 
			
		||||
				but->flag |= UI_BUT_DISABLED;
 | 
			
		||||
				but->lock = 1;
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -2064,7 +2064,7 @@ static void operator_search_cb(const bContext *C, void *arg, char *str, uiSearch
 | 
			
		||||
	for(; ot; ot= ot->next) {
 | 
			
		||||
		
 | 
			
		||||
		if(BLI_strcasestr(ot->name, str)) {
 | 
			
		||||
			if(ot->poll==NULL || ot->poll((bContext *)C)) {
 | 
			
		||||
			if(WM_operator_poll((bContext*)C, ot)) {
 | 
			
		||||
				char name[256];
 | 
			
		||||
				int len= strlen(ot->name);
 | 
			
		||||
				
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
 | 
			
		||||
	
 | 
			
		||||
	if(op==NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	if(op->type->poll && op->type->poll((bContext *)C)==0)
 | 
			
		||||
	if(WM_operator_poll((bContext*)C, op->type) == 0)
 | 
			
		||||
		return;
 | 
			
		||||
	
 | 
			
		||||
	block= uiLayoutGetBlock(pa->layout);
 | 
			
		||||
@@ -208,7 +208,7 @@ static void operator_search_cb(const struct bContext *C, void *arg, char *str, u
 | 
			
		||||
	for(; ot; ot= ot->next) {
 | 
			
		||||
		
 | 
			
		||||
		if(BLI_strcasestr(ot->name, str)) {
 | 
			
		||||
			if(ot->poll==NULL || ot->poll((bContext *)C)) {
 | 
			
		||||
			if(WM_operator_poll((bContext*)C, ot)) {
 | 
			
		||||
				
 | 
			
		||||
				if(0==uiSearchItemAdd(items, ot->name, ot, 0))
 | 
			
		||||
					break;
 | 
			
		||||
 
 | 
			
		||||
@@ -228,6 +228,7 @@ typedef struct wmOperatorType {
 | 
			
		||||
	/* only used for operators defined with python
 | 
			
		||||
	 * use to store pointers to python functions */
 | 
			
		||||
	void *pyop_data;
 | 
			
		||||
	int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot);
 | 
			
		||||
 | 
			
		||||
} wmOperatorType;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if(ot->poll && (ot->poll(C) == FALSE)) {
 | 
			
		||||
	if(WM_operator_poll((bContext*)C, ot) == FALSE) {
 | 
			
		||||
		PyErr_SetString( PyExc_SystemError, "bpy.__ops__.call: operator poll() function failed, context is incorrect");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -81,9 +81,9 @@ static struct BPY_flag_def pyop_ret_flags[] = {
 | 
			
		||||
	
 | 
			
		||||
extern void BPY_update_modules( void ); //XXX temp solution
 | 
			
		||||
 | 
			
		||||
static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event)
 | 
			
		||||
static int PYTHON_OT_generic(int mode, bContext *C, wmOperatorType *ot, wmOperator *op, wmEvent *event)
 | 
			
		||||
{
 | 
			
		||||
	PyObject *py_class = op->type->pyop_data;
 | 
			
		||||
	PyObject *py_class = ot->pyop_data;
 | 
			
		||||
	PyObject *args;
 | 
			
		||||
	PyObject *ret= NULL, *py_class_instance, *item= NULL;
 | 
			
		||||
	int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
 | 
			
		||||
@@ -105,7 +105,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		/* Assign instance attributes from operator properties */
 | 
			
		||||
		{
 | 
			
		||||
		if(op) {
 | 
			
		||||
			const char *arg_name;
 | 
			
		||||
 | 
			
		||||
			RNA_STRUCT_BEGIN(op->ptr, prop) {
 | 
			
		||||
@@ -121,10 +121,12 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* set operator pointer RNA as instance "__operator__" attribute */
 | 
			
		||||
		if(op) {
 | 
			
		||||
			RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
 | 
			
		||||
			py_operator= pyrna_struct_CreatePyObject(&ptr_operator);
 | 
			
		||||
			PyObject_SetAttrString(py_class_instance, "__operator__", py_operator);
 | 
			
		||||
			Py_DECREF(py_operator);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
 | 
			
		||||
		
 | 
			
		||||
@@ -148,8 +150,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
		else if (mode==PYOP_POLL) {
 | 
			
		||||
			item= PyObject_GetAttrString(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, 1, pyrna_struct_CreatePyObject(&ptr_context));
 | 
			
		||||
		}
 | 
			
		||||
		PyTuple_SET_ITEM(args, 0, py_class_instance);
 | 
			
		||||
	
 | 
			
		||||
@@ -160,12 +161,14 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if (ret == NULL) { /* covers py_class_instance failing too */
 | 
			
		||||
		if(op)
 | 
			
		||||
			BPy_errors_to_report(op->reports);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		if (mode==PYOP_POLL) {
 | 
			
		||||
			if (PyBool_Check(ret) == 0) {
 | 
			
		||||
				PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
 | 
			
		||||
				if(op)
 | 
			
		||||
					BPy_errors_to_report(op->reports);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
@@ -174,6 +177,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
			
 | 
			
		||||
		} else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
 | 
			
		||||
			/* the returned value could not be converted into a flag */
 | 
			
		||||
			if(op)
 | 
			
		||||
				BPy_errors_to_report(op->reports);
 | 
			
		||||
 | 
			
		||||
			ret_flag = OPERATOR_CANCELLED;
 | 
			
		||||
@@ -225,19 +229,17 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
 | 
			
		||||
 | 
			
		||||
static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
 | 
			
		||||
{
 | 
			
		||||
	return PYTHON_OT_generic(PYOP_INVOKE, C, op, event);	
 | 
			
		||||
	return PYTHON_OT_generic(PYOP_INVOKE, C, op->type, op, event);	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int PYTHON_OT_execute(bContext *C, wmOperator *op)
 | 
			
		||||
{
 | 
			
		||||
	return PYTHON_OT_generic(PYOP_EXEC, C, op, NULL);
 | 
			
		||||
	return PYTHON_OT_generic(PYOP_EXEC, C, op->type, op, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int PYTHON_OT_poll(bContext *C)
 | 
			
		||||
static int PYTHON_OT_poll(bContext *C, wmOperatorType *ot)
 | 
			
		||||
{
 | 
			
		||||
	// 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;
 | 
			
		||||
	return PYTHON_OT_generic(PYOP_POLL, C, ot, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
 | 
			
		||||
@@ -270,7 +272,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
 | 
			
		||||
	if (PyObject_HasAttrString(py_class, "execute"))
 | 
			
		||||
		ot->exec= PYTHON_OT_execute;
 | 
			
		||||
	if (PyObject_HasAttrString(py_class, "poll"))
 | 
			
		||||
		ot->poll= PYTHON_OT_poll;
 | 
			
		||||
		ot->pyop_poll= PYTHON_OT_poll;
 | 
			
		||||
	
 | 
			
		||||
	ot->pyop_data= userdata;
 | 
			
		||||
	
 | 
			
		||||
 
 | 
			
		||||
@@ -162,6 +162,7 @@ wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag)
 | 
			
		||||
wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int			WM_operator_poll		(struct bContext *C, struct wmOperatorType *ot);
 | 
			
		||||
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);
 | 
			
		||||
 
 | 
			
		||||
@@ -259,18 +259,21 @@ void wm_event_do_notifiers(bContext *C)
 | 
			
		||||
 | 
			
		||||
/* ********************* operators ******************* */
 | 
			
		||||
 | 
			
		||||
static int wm_operator_poll(bContext *C, wmOperatorType *ot)
 | 
			
		||||
int WM_operator_poll(bContext *C, wmOperatorType *ot)
 | 
			
		||||
{
 | 
			
		||||
	wmOperatorTypeMacro *otmacro;
 | 
			
		||||
	
 | 
			
		||||
	for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
 | 
			
		||||
		wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
 | 
			
		||||
		
 | 
			
		||||
		if(0==wm_operator_poll(C, ot))
 | 
			
		||||
		if(0==WM_operator_poll(C, ot))
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	if(ot->poll)
 | 
			
		||||
	/* python needs operator type, so we added exception for it */
 | 
			
		||||
	if(ot->pyop_poll)
 | 
			
		||||
		return ot->pyop_poll(C, ot);
 | 
			
		||||
	else if(ot->poll)
 | 
			
		||||
		return ot->poll(C);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -284,7 +287,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
 | 
			
		||||
	if(op==NULL || op->type==NULL)
 | 
			
		||||
		return retval;
 | 
			
		||||
	
 | 
			
		||||
	if(0==wm_operator_poll(C, op->type))
 | 
			
		||||
	if(0==WM_operator_poll(C, op->type))
 | 
			
		||||
		return retval;
 | 
			
		||||
	
 | 
			
		||||
	if(op->type->exec)
 | 
			
		||||
@@ -397,7 +400,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
 | 
			
		||||
	wmWindowManager *wm= CTX_wm_manager(C);
 | 
			
		||||
	int retval= OPERATOR_PASS_THROUGH;
 | 
			
		||||
 | 
			
		||||
	if(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 */
 | 
			
		||||
		
 | 
			
		||||
		if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
 | 
			
		||||
 
 | 
			
		||||
@@ -682,7 +682,7 @@ static void operator_search_cb(const struct bContext *C, void *arg, char *str, u
 | 
			
		||||
	for(; ot; ot= ot->next) {
 | 
			
		||||
		
 | 
			
		||||
		if(BLI_strcasestr(ot->name, str)) {
 | 
			
		||||
			if(ot->poll==NULL || ot->poll((bContext *)C)) {
 | 
			
		||||
			if(WM_operator_poll((bContext*)C, ot)) {
 | 
			
		||||
				char name[256];
 | 
			
		||||
				int len= strlen(ot->name);
 | 
			
		||||
				
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user