* operators now return sets (converted into flags) * can't remove bpy_operator_wrap.c since macro's still use the custom register funcs
		
			
				
	
	
		
			673 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			673 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /**
 | |
|  * $Id$
 | |
|  *
 | |
|  * ***** BEGIN GPL LICENSE BLOCK *****
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | |
|  *
 | |
|  * Contributor(s): Campbell Barton
 | |
|  *
 | |
|  * ***** END GPL LICENSE BLOCK *****
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include "bpy_operator_wrap.h"
 | |
| #include "BLI_listbase.h"
 | |
| #include "BKE_context.h"
 | |
| #include "BKE_report.h"
 | |
| #include "DNA_windowmanager_types.h"
 | |
| #include "MEM_guardedalloc.h"
 | |
| #include "WM_api.h"
 | |
| #include "WM_types.h"
 | |
| #include "UI_interface.h"
 | |
| #include "ED_screen.h"
 | |
| 
 | |
| #include "RNA_define.h"
 | |
| 
 | |
| #include "bpy_rna.h"
 | |
| #include "bpy_util.h"
 | |
| 
 | |
| #include "../generic/bpy_internal_import.h" // our own imports
 | |
| 
 | |
| #define PYOP_ATTR_UINAME		"bl_label"
 | |
| #define PYOP_ATTR_IDNAME		"bl_idname"		/* the name given by python */
 | |
| #define PYOP_ATTR_IDNAME_BL	"_bl_idname"	/* our own name converted into blender syntax, users wont see this */
 | |
| #define PYOP_ATTR_DESCRIPTION	"__doc__"		/* use pythons docstring */
 | |
| #define PYOP_ATTR_REGISTER		"bl_register"	/* True/False. if this python operator should be registered */
 | |
| #define PYOP_ATTR_UNDO			"bl_undo"		/* True/False. if this python operator should be undone */
 | |
| 
 | |
| static struct BPY_flag_def pyop_ret_flags[] = {
 | |
| 	{"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
 | |
| 	{"CANCELLED", OPERATOR_CANCELLED},
 | |
| 	{"FINISHED", OPERATOR_FINISHED},
 | |
| 	{"PASS_THROUGH", OPERATOR_PASS_THROUGH},
 | |
| 	{NULL, 0}
 | |
| };
 | |
| 
 | |
| /* This invoke function can take events and
 | |
|  *
 | |
|  * It is up to the pyot->py_invoke() python func to run pyot->py_exec()
 | |
|  * the invoke function gets the keyword props as a dict, but can parse them
 | |
|  * to py_exec like this...
 | |
|  *
 | |
|  * def op_exec(x=-1, y=-1, text=""):
 | |
|  *     ...
 | |
|  *
 | |
|  * def op_invoke(event, prop_defs):
 | |
|  *     prop_defs['x'] = event['x']
 | |
|  *     ...
 | |
|  *     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
 | |
|  */
 | |
| 
 | |
| 
 | |
| #define PYOP_EXEC 1
 | |
| #define PYOP_INVOKE 2
 | |
| #define PYOP_POLL 3
 | |
| #define PYOP_DRAW 4
 | |
| 	
 | |
| extern void BPY_update_modules( void ); //XXX temp solution
 | |
| 
 | |
| static int PYTHON_OT_generic(int mode, bContext *C, wmOperatorType *ot, wmOperator *op, wmEvent *event, uiLayout *layout)
 | |
| {
 | |
| 	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);
 | |
| 	PointerRNA ptr_context;
 | |
| 	PointerRNA ptr_operator;
 | |
| 
 | |
| 	PyGILState_STATE gilstate;
 | |
| 
 | |
| 	bpy_context_set(C, &gilstate);
 | |
| 
 | |
| 	args = PyTuple_New(1);
 | |
| 
 | |
| 	/* poll has no 'op', should be ok still */
 | |
| 	/* use an rna instance as the first arg */
 | |
| 	RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
 | |
| 	PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&ptr_operator));
 | |
| 
 | |
| 	py_class_instance = PyObject_Call(py_class, args, NULL);
 | |
| 	Py_DECREF(args);
 | |
| 
 | |
| 	if (py_class_instance==NULL) { /* Initializing the class worked, now run its invoke function */
 | |
| 		PyErr_Print();
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 	else {
 | |
| 		RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
 | |
| 
 | |
| 		if (mode==PYOP_INVOKE) {
 | |
| 			PointerRNA ptr_event;
 | |
| 			item= PyObject_GetAttrString(py_class, "invoke");
 | |
| 			args = PyTuple_New(3);
 | |
| 
 | |
| 			RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event);
 | |
| 
 | |
| 			// PyTuple_SET_ITEM "steals" object reference, it is
 | |
| 			// an object passed shouldn't be DECREF'ed
 | |
| 			PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
 | |
| 			PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event));
 | |
| 		}
 | |
| 		else if (mode==PYOP_EXEC) {
 | |
| 			item= PyObject_GetAttrString(py_class, "execute");
 | |
| 			args = PyTuple_New(2);
 | |
| 
 | |
| 			PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
 | |
| 		}
 | |
| 		else if (mode==PYOP_POLL) {
 | |
| 			item= PyObject_GetAttrString(py_class, "poll");
 | |
| 			args = PyTuple_New(2);
 | |
| 			PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
 | |
| 		}
 | |
| 		else if (mode==PYOP_DRAW) {
 | |
| 			PointerRNA ptr_layout;
 | |
| 			item= PyObject_GetAttrString(py_class, "draw");
 | |
| 			args = PyTuple_New(2);
 | |
| 
 | |
| 			RNA_pointer_create(NULL, &RNA_UILayout, layout, &ptr_layout);
 | |
| 
 | |
| 			// PyTuple_SET_ITEM "steals" object reference, it is
 | |
| 			// an object passed shouldn't be DECREF'ed
 | |
| 			PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
 | |
| #if 0
 | |
| 			PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_layout));
 | |
| #else
 | |
| 			{
 | |
| 				/* mimic panels */
 | |
| 				PyObject *py_layout= pyrna_struct_CreatePyObject(&ptr_layout);
 | |
| 				PyObject *pyname= PyUnicode_FromString("layout");
 | |
| 
 | |
| 				if(PyObject_GenericSetAttr(py_class_instance, pyname, py_layout)) {
 | |
| 					PyErr_Print();
 | |
| 					PyErr_Clear();
 | |
| 				}
 | |
| 				else {
 | |
| 					Py_DECREF(py_layout);
 | |
| 				}
 | |
| 
 | |
| 				Py_DECREF(pyname);
 | |
| 			}
 | |
| #endif
 | |
| 		}
 | |
| 		PyTuple_SET_ITEM(args, 0, py_class_instance);
 | |
| 
 | |
| 		ret = PyObject_Call(item, args, NULL);
 | |
| 
 | |
| 		Py_DECREF(args);
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 
 | |
| 	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_Format(PyExc_ValueError, "Python operator '%s.poll', did not return a bool value", ot->idname);
 | |
| 				BPy_errors_to_report(op ? op->reports:NULL); /* prints and clears if NULL given */
 | |
| 			}
 | |
| 			else {
 | |
| 				ret_flag= ret==Py_True ? 1:0;
 | |
| 			}
 | |
| 		} else if(mode==PYOP_DRAW) {
 | |
| 			/* pass */
 | |
| 		} else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
 | |
| 			/* the returned value could not be converted into a flag */
 | |
| 			PyErr_Format(PyExc_ValueError, "Python operator, error using return value from \"%s\"\n", ot->idname);
 | |
| 			BPy_errors_to_report(op ? op->reports:NULL);
 | |
| 			ret_flag = OPERATOR_CANCELLED;
 | |
| 		}
 | |
| 		/* there is no need to copy the py keyword dict modified by
 | |
| 		 * pyot->py_invoke(), back to the operator props since they are just
 | |
| 		 * thrown away anyway
 | |
| 		 *
 | |
| 		 * If we ever want to do this and use the props again,
 | |
| 		 * it can be done with - pyrna_pydict_to_props(op->ptr, kw, "")
 | |
| 		 */
 | |
| 
 | |
| 		Py_DECREF(ret);
 | |
| 	}
 | |
| 
 | |
| #if 0 /* only for testing */
 | |
| 
 | |
| 	/* print operator return value */
 | |
| 	if (mode != PYOP_POLL) {
 | |
| 		char flag_str[100];
 | |
| 		char class_name[100];
 | |
| 		BPY_flag_def *flag_def = pyop_ret_flags;
 | |
| 
 | |
| 		strcpy(flag_str, "");
 | |
| 
 | |
| 		while(flag_def->name) {
 | |
| 			if (ret_flag & flag_def->flag) {
 | |
| 				if(flag_str[1])
 | |
| 					sprintf(flag_str, "%s | %s", flag_str, flag_def->name);
 | |
| 				else
 | |
| 					strcpy(flag_str, flag_def->name);
 | |
| 			}
 | |
| 			flag_def++;
 | |
| 		}
 | |
| 
 | |
| 		/* get class name */
 | |
| 		item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
 | |
| 		strcpy(class_name, _PyUnicode_AsString(item));
 | |
| 		Py_DECREF(item);
 | |
| 
 | |
| 		fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str);
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	bpy_context_clear(C, &gilstate);
 | |
| 
 | |
| 	return ret_flag;
 | |
| }
 | |
| 
 | |
| static int PYTHON_OT_invoke(bContext *C, wmOperator *op, wmEvent *event)
 | |
| {
 | |
| 	return PYTHON_OT_generic(PYOP_INVOKE, C, op->type, op, event, NULL);
 | |
| }
 | |
| 
 | |
| static int PYTHON_OT_execute(bContext *C, wmOperator *op)
 | |
| {
 | |
| 	return PYTHON_OT_generic(PYOP_EXEC, C, op->type, op, NULL, NULL);
 | |
| }
 | |
| 
 | |
| static int PYTHON_OT_poll(bContext *C, wmOperatorType *ot)
 | |
| {
 | |
| 	return PYTHON_OT_generic(PYOP_POLL, C, ot, NULL, NULL, NULL);
 | |
| }
 | |
| 
 | |
| static void PYTHON_OT_draw(bContext *C, wmOperator *op, uiLayout *layout)
 | |
| {
 | |
| 	PYTHON_OT_generic(PYOP_DRAW, C, op->type, op, NULL, layout);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void operator_wrapper(wmOperatorType *ot, void *userdata)
 | |
| {
 | |
| 	/* take care not to overwrite anything set in
 | |
| 	 * WM_operatortype_append_ptr before opfunc() is called */
 | |
| 	StructRNA *srna = ot->srna;
 | |
| 	*ot= *((wmOperatorType *)userdata);
 | |
| 	ot->srna= srna; /* restore */
 | |
| 
 | |
| 	RNA_struct_blender_type_set(ot->ext.srna, ot);
 | |
| 
 | |
| 
 | |
| 	/* Can't use this because it returns a dict proxy
 | |
| 	 *
 | |
| 	 * item= PyObject_GetAttrString(py_class, "__dict__");
 | |
| 	 */
 | |
| 	{
 | |
| 		PyObject *py_class = ot->ext.data;
 | |
| 		PyObject *item= ((PyTypeObject*)py_class)->tp_dict;
 | |
| 		if(item) {
 | |
| 			/* only call this so pyrna_deferred_register_props gives a useful error
 | |
| 			 * WM_operatortype_append_ptr will call RNA_def_struct_identifier
 | |
| 			 * later */
 | |
| 			RNA_def_struct_identifier(ot->srna, ot->idname);
 | |
| 
 | |
| 			if(pyrna_deferred_register_props(ot->srna, item)!=0) {
 | |
| 				/* failed to register operator props */
 | |
| 				PyErr_Print();
 | |
| 				PyErr_Clear();
 | |
| 
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			PyErr_Clear();
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
 | |
| {
 | |
| 	PyObject *py_class = (PyObject *)userdata;
 | |
| 	PyObject *item;
 | |
| 
 | |
| 	/* identifiers */
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL);
 | |
| 	ot->idname= _PyUnicode_AsString(item);
 | |
| 	Py_DECREF(item);
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
 | |
| 	if (item) {
 | |
| 		ot->name= _PyUnicode_AsString(item);
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		ot->name= ot->idname;
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
 | |
| 	ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
 | |
| 	Py_XDECREF(item);
 | |
| 
 | |
| 	/* api callbacks, detailed checks dont on adding */
 | |
| 	if (PyObject_HasAttrString(py_class, "invoke"))
 | |
| 		ot->invoke= PYTHON_OT_invoke;
 | |
| 	//else
 | |
| 	//	ot->invoke= WM_operator_props_popup; /* could have an option for standard invokes */
 | |
| 
 | |
| 	if (PyObject_HasAttrString(py_class, "execute"))
 | |
| 		ot->exec= PYTHON_OT_execute;
 | |
| 	if (PyObject_HasAttrString(py_class, "poll"))
 | |
| 		ot->pyop_poll= PYTHON_OT_poll;
 | |
| 	if (PyObject_HasAttrString(py_class, "draw"))
 | |
| 		ot->ui= PYTHON_OT_draw;
 | |
| 
 | |
| 	ot->pyop_data= userdata;
 | |
| 
 | |
| 	/* flags */
 | |
| 	ot->flag= 0;
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
 | |
| 	if (item) {
 | |
| 		ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO);
 | |
| 	if (item) {
 | |
| 		ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0;
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 
 | |
| 	/* Can't use this because it returns a dict proxy
 | |
| 	 *
 | |
| 	 * item= PyObject_GetAttrString(py_class, "__dict__");
 | |
| 	 */
 | |
| 	item= ((PyTypeObject*)py_class)->tp_dict;
 | |
| 	if(item) {
 | |
| 		/* only call this so pyrna_deferred_register_props gives a useful error
 | |
| 		 * WM_operatortype_append_ptr will call RNA_def_struct_identifier
 | |
| 		 * later */
 | |
| 		RNA_def_struct_identifier(ot->srna, ot->idname);
 | |
| 
 | |
| 		if(pyrna_deferred_register_props(ot->srna, item)!=0) {
 | |
| 			/* failed to register operator props */
 | |
| 			PyErr_Print();
 | |
| 			PyErr_Clear();
 | |
| 
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void PYTHON_OT_MACRO_wrapper(wmOperatorType *ot, void *userdata)
 | |
| {
 | |
| 	PyObject *py_class = (PyObject *)userdata;
 | |
| 	PyObject *item;
 | |
| 
 | |
| 	/* identifiers */
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME_BL);
 | |
| 	ot->idname= _PyUnicode_AsString(item);
 | |
| 	Py_DECREF(item);
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
 | |
| 	if (item) {
 | |
| 		ot->name= _PyUnicode_AsString(item);
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		ot->name= ot->idname;
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
 | |
| 	ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"undocumented python operator";
 | |
| 	Py_XDECREF(item);
 | |
| 
 | |
| 	if (PyObject_HasAttrString(py_class, "poll"))
 | |
| 		ot->pyop_poll= PYTHON_OT_poll;
 | |
| 	if (PyObject_HasAttrString(py_class, "draw"))
 | |
| 		ot->ui= PYTHON_OT_draw;
 | |
| 
 | |
| 	ot->pyop_data= userdata;
 | |
| 
 | |
| 	/* flags */
 | |
| 	ot->flag= OPTYPE_MACRO; /* macro at least */
 | |
| 
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER);
 | |
| 	if (item) {
 | |
| 		ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0;
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO);
 | |
| 	if (item) {
 | |
| 		ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0;
 | |
| 		Py_DECREF(item);
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| 
 | |
| 	/* Can't use this because it returns a dict proxy
 | |
| 	 *
 | |
| 	 * item= PyObject_GetAttrString(py_class, "__dict__");
 | |
| 	 */
 | |
| 	item= ((PyTypeObject*)py_class)->tp_dict;
 | |
| 	if(item) {
 | |
| 		/* only call this so pyrna_deferred_register_props gives a useful error
 | |
| 		 * WM_operatortype_append_macro_ptr will call RNA_def_struct_identifier
 | |
| 		 * later */
 | |
| 		RNA_def_struct_identifier(ot->srna, ot->idname);
 | |
| 
 | |
| 		if(pyrna_deferred_register_props(ot->srna, item)!=0) {
 | |
| 			/* failed to register operator props */
 | |
| 			PyErr_Print();
 | |
| 			PyErr_Clear();
 | |
| 
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		PyErr_Clear();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /* pyOperators - Operators defined IN Python */
 | |
| PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
 | |
| {
 | |
| 	PyObject *base_class, *item;
 | |
| 	wmOperatorType *ot;
 | |
| 
 | |
| 
 | |
| 	char *idname= NULL;
 | |
| 	char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
 | |
| 
 | |
| 	static struct BPY_class_attr_check pyop_class_attr_values[]= {
 | |
| 		{PYOP_ATTR_IDNAME,		's', -1, OP_MAX_TYPENAME-3,	0}, /* -3 because a.b -> A_OT_b */
 | |
| 		{PYOP_ATTR_UINAME,		's', -1,-1,	BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{PYOP_ATTR_DESCRIPTION,	's', -1,-1,	BPY_CLASS_ATTR_NONE_OK},
 | |
| 		{"execute",				'f', 2,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{"invoke",				'f', 3,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{"poll",				'f', 2,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{"draw",				'f', 2,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{NULL, 0, 0, 0}
 | |
| 	};
 | |
| 
 | |
| 	// in python would be...
 | |
| 	//PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator");
 | |
| 
 | |
| 	//PyObject bpy_mod= PyDict_GetItemString(PyEval_GetGlobals(), "bpy");
 | |
| 	PyObject *bpy_mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
 | |
| 	base_class = PyObject_GetAttrStringArgs(bpy_mod, 2, "types", "Operator");
 | |
| 	Py_DECREF(bpy_mod);
 | |
| 
 | |
| 	if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
 | |
| 		return NULL; /* BPY_class_validate sets the error */
 | |
| 	}
 | |
| 	Py_DECREF(base_class);
 | |
| 
 | |
| 	/* class name is used for operator ID - this can be changed later if we want */
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
 | |
| 	idname =  _PyUnicode_AsString(item);
 | |
| 
 | |
| 
 | |
| 	/* annoying conversion! */
 | |
| 	WM_operator_bl_idname(idname_bl, idname);
 | |
| 	Py_DECREF(item);
 | |
| 
 | |
| 	item= PyUnicode_FromString(idname_bl);
 | |
| 	PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item);
 | |
| 	idname =  _PyUnicode_AsString(item);
 | |
| 	Py_DECREF(item);
 | |
| 	/* end annoying conversion! */
 | |
| 
 | |
| 
 | |
| 	/* remove if it already exists */
 | |
| 	if ((ot=WM_operatortype_exists(idname))) {
 | |
| 		if(ot->pyop_data) {
 | |
| 			Py_XDECREF((PyObject*)ot->pyop_data);
 | |
| 		}
 | |
| 		WM_operatortype_remove(idname);
 | |
| 	}
 | |
| 
 | |
| 	Py_INCREF(py_class);
 | |
| 	WM_operatortype_append_ptr(PYTHON_OT_wrapper, py_class);
 | |
| 
 | |
| 	Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| /* pyOperators - Macro Operators defined IN Python */
 | |
| PyObject *PYOP_wrap_add_macro(PyObject *self, PyObject *py_class)
 | |
| {
 | |
| 	PyObject *base_class, *item;
 | |
| 	wmOperatorType *ot;
 | |
| 
 | |
| 
 | |
| 	char *idname= NULL;
 | |
| 	char idname_bl[OP_MAX_TYPENAME]; /* converted to blender syntax */
 | |
| 
 | |
| 	static struct BPY_class_attr_check pyop_class_attr_values[]= {
 | |
| 		{PYOP_ATTR_IDNAME,		's', -1, OP_MAX_TYPENAME-3,	0}, /* -3 because a.b -> A_OT_b */
 | |
| 		{PYOP_ATTR_UINAME,		's', -1,-1,	BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{PYOP_ATTR_DESCRIPTION,	's', -1,-1,	BPY_CLASS_ATTR_NONE_OK},
 | |
| 		{"poll",				'f', 2,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{"draw",				'f', 2,	-1, BPY_CLASS_ATTR_OPTIONAL},
 | |
| 		{NULL, 0, 0, 0}
 | |
| 	};
 | |
| 
 | |
| 	//PyObject bpy_mod= PyDict_GetItemString(PyEval_GetGlobals(), "bpy");
 | |
| 	PyObject *bpy_mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
 | |
| 	base_class = PyObject_GetAttrStringArgs(bpy_mod, 2, "types", "Macro");
 | |
| 	Py_DECREF(bpy_mod);
 | |
| 
 | |
| 	if(BPY_class_validate("Macro", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
 | |
| 		return NULL; /* BPY_class_validate sets the error */
 | |
| 	}
 | |
| 	Py_DECREF(base_class);
 | |
| 
 | |
| 	/* class name is used for operator ID - this can be changed later if we want */
 | |
| 	item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
 | |
| 	idname =  _PyUnicode_AsString(item);
 | |
| 
 | |
| 
 | |
| 	/* annoying conversion! */
 | |
| 	WM_operator_bl_idname(idname_bl, idname);
 | |
| 	Py_DECREF(item);
 | |
| 
 | |
| 	item= PyUnicode_FromString(idname_bl);
 | |
| 	PyObject_SetAttrString(py_class, PYOP_ATTR_IDNAME_BL, item);
 | |
| 	idname =  _PyUnicode_AsString(item);
 | |
| 	Py_DECREF(item);
 | |
| 	/* end annoying conversion! */
 | |
| 
 | |
| 
 | |
| 	/* remove if it already exists */
 | |
| 	if ((ot=WM_operatortype_exists(idname))) {
 | |
| 		if(ot->pyop_data) {
 | |
| 			Py_XDECREF((PyObject*)ot->pyop_data);
 | |
| 		}
 | |
| 		WM_operatortype_remove(idname);
 | |
| 	}
 | |
| 
 | |
| 	Py_INCREF(py_class);
 | |
| 	WM_operatortype_append_macro_ptr(PYTHON_OT_MACRO_wrapper, py_class);
 | |
| 
 | |
| 	Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args)
 | |
| {
 | |
| 	wmOperatorType *ot;
 | |
| 	wmOperatorTypeMacro *otmacro;
 | |
| 	PyObject *macro;
 | |
| 	PyObject *item;
 | |
| 	PointerRNA ptr_otmacro;
 | |
| 
 | |
| 	char *opname;
 | |
| 	char *macroname;
 | |
| 
 | |
| 	if (!PyArg_ParseTuple(args, "Os:_bpy.ops.macro_define", ¯o, &opname))
 | |
| 		return NULL;
 | |
| 
 | |
| 	if (WM_operatortype_exists(opname) == NULL) {
 | |
| 		PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid operator id", opname);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	/* identifiers */
 | |
| 	item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME_BL);
 | |
| 
 | |
| 	if (!item) {
 | |
| 		item= PyObject_GetAttrString(macro, PYOP_ATTR_IDNAME);
 | |
| 
 | |
| 		if (!item) {
 | |
| 			PyErr_Format(PyExc_ValueError, "Macro Define: not a valid Macro class");
 | |
| 		} else {
 | |
| 			macroname= _PyUnicode_AsString(item);
 | |
| 			PyErr_Format(PyExc_ValueError, "Macro Define: '%s' hasn't been registered yet", macroname);
 | |
| 		}
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	macroname= _PyUnicode_AsString(item);
 | |
| 
 | |
| 	ot = WM_operatortype_exists(macroname);
 | |
| 
 | |
| 	if (!ot) {
 | |
| 		PyErr_Format(PyExc_ValueError, "Macro Define: '%s' is not a valid macro or hasn't been registered yet", macroname);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	otmacro = WM_operatortype_macro_define(ot, opname);
 | |
| 
 | |
| 	RNA_pointer_create(NULL, &RNA_OperatorTypeMacro, otmacro, &ptr_otmacro);
 | |
| 
 | |
| 	return pyrna_struct_CreatePyObject(&ptr_otmacro);
 | |
| }
 | |
| 
 | |
| 
 | |
| PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
 | |
| {
 | |
| 	PyObject *py_class;
 | |
| 	char *idname= NULL;
 | |
| 	wmOperatorType *ot;
 | |
| 	
 | |
| 
 | |
| 	if (PyUnicode_Check(value))
 | |
| 		idname = _PyUnicode_AsString(value);
 | |
| 	else if (PyCFunction_Check(value)) {
 | |
| 		PyObject *cfunc_self = PyCFunction_GetSelf(value);
 | |
| 		if (cfunc_self)
 | |
| 			idname = _PyUnicode_AsString(cfunc_self);
 | |
| 	}
 | |
| 	
 | |
| 	if (idname==NULL) {
 | |
| 		PyErr_SetString( PyExc_ValueError, "Expected the operator name as a string or the operator function");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (!(ot= WM_operatortype_exists(idname))) {
 | |
| 		PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	
 | |
| 	if (!(py_class= (PyObject *)ot->pyop_data)) {
 | |
| 		PyErr_Format( PyExc_AttributeError, "Operator \"%s\" was not created by python", idname);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	
 | |
| 	Py_XDECREF(py_class);
 | |
| 
 | |
| 	WM_operatortype_remove(idname);
 | |
| 
 | |
| 	Py_RETURN_NONE;
 | |
| }
 |