Python Panels WIP
- Register python panels - Added a generic class checking function BPY_class_validate() for panels/operators. - No button drawing yet Brecht, Added RNA_enum_value_from_id() and RNA_enum_id_from_value() to rna_access.c to do lookups between identifiers and values of EnumPropertyItem's, Not sure if these should go here.
This commit is contained in:
@@ -139,7 +139,8 @@ extern "C" {
|
||||
void BPY_scripts_clear_pyobjects( void );
|
||||
|
||||
void error_pyscript( void );
|
||||
|
||||
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
|
||||
|
||||
/* void BPY_Err_Handle(struct Text *text); */
|
||||
/* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */
|
||||
/* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */
|
||||
|
||||
@@ -241,6 +241,11 @@ int BPY_run_script_space_listener(bContext *C, SpaceScript * sc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BPY_DECREF(void *pyob_ptr)
|
||||
{
|
||||
Py_DECREF((PyObject *)pyob_ptr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* called from the the scripts window, assume context is ok */
|
||||
int BPY_run_python_script_space(const char *modulename, const char *func)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "bpy_operator.h"
|
||||
#include "bpy_opwrapper.h"
|
||||
#include "bpy_operator_wrap.h"
|
||||
#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
|
||||
#include "bpy_compat.h"
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "bpy_opwrapper.h"
|
||||
#include "bpy_operator_wrap.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
@@ -45,14 +45,6 @@
|
||||
#define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */
|
||||
#define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */
|
||||
|
||||
typedef struct PyOperatorType {
|
||||
void *next, *prev;
|
||||
char idname[OP_MAX_TYPENAME];
|
||||
char name[OP_MAX_TYPENAME];
|
||||
char description[OP_MAX_TYPENAME]; // XXX should be longer?
|
||||
PyObject *py_class;
|
||||
} PyOperatorType;
|
||||
|
||||
static PyObject *pyop_dict_from_event(wmEvent *event)
|
||||
{
|
||||
PyObject *dict= PyDict_New();
|
||||
@@ -191,14 +183,16 @@ static struct BPY_flag_def pyop_ret_flags[] = {
|
||||
|
||||
static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
PyOperatorType *pyot = op->type->pyop_data;
|
||||
PyObject *py_class = op->type->pyop_data;
|
||||
PyObject *args;
|
||||
PyObject *ret= NULL, *py_class_instance, *item;
|
||||
int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
|
||||
|
||||
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
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);
|
||||
PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg
|
||||
py_class_instance = PyObject_Call(py_class, args, NULL);
|
||||
Py_DECREF(args);
|
||||
|
||||
if (py_class_instance) { /* Initializing the class worked, now run its invoke function */
|
||||
@@ -229,16 +223,16 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
|
||||
|
||||
|
||||
if (mode==PYOP_INVOKE) {
|
||||
item= PyObject_GetAttrString(pyot->py_class, "invoke");
|
||||
item= PyObject_GetAttrString(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");
|
||||
item= PyObject_GetAttrString(py_class, "exec");
|
||||
args = PyTuple_New(1);
|
||||
}
|
||||
else if (mode==PYOP_POLL) {
|
||||
item= PyObject_GetAttrString(pyot->py_class, "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);
|
||||
@@ -251,7 +245,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
if (ret == NULL) { /* covers py_class_instance failing too */
|
||||
pyop_error_report(op->reports);
|
||||
}
|
||||
else {
|
||||
@@ -280,6 +274,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
||||
return ret_flag;
|
||||
}
|
||||
|
||||
@@ -302,15 +298,29 @@ static int PYTHON_OT_poll(bContext *C)
|
||||
|
||||
void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
|
||||
{
|
||||
PyOperatorType *pyot = (PyOperatorType *)userdata;
|
||||
PyObject *py_class = pyot->py_class;
|
||||
PyObject *py_class = (PyObject *)userdata;
|
||||
PyObject *props, *item;
|
||||
|
||||
/* identifiers */
|
||||
ot->name= pyot->name;
|
||||
ot->idname= pyot->idname;
|
||||
ot->description= pyot->description;
|
||||
item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
|
||||
Py_DECREF(item);
|
||||
ot->idname= _PyUnicode_AsString(item);
|
||||
|
||||
|
||||
item= PyObject_GetAttrString(py_class, PYOP_ATTR_UINAME);
|
||||
if (item) {
|
||||
Py_DECREF(item);
|
||||
ot->name= _PyUnicode_AsString(item);
|
||||
}
|
||||
else {
|
||||
ot->name= ot->idname;
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
item= PyObject_GetAttrString(py_class, PYOP_ATTR_DESCRIPTION);
|
||||
Py_DECREF(item);
|
||||
ot->description= (item && PyUnicode_Check(item)) ? _PyUnicode_AsString(item):"";
|
||||
|
||||
/* api callbacks, detailed checks dont on adding */
|
||||
if (PyObject_HasAttrString(py_class, "invoke"))
|
||||
ot->invoke= PYTHON_OT_invoke;
|
||||
@@ -364,105 +374,48 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
|
||||
|
||||
|
||||
/* pyOperators - Operators defined IN Python */
|
||||
PyObject *PYOP_wrap_add(PyObject *self, PyObject *value)
|
||||
PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
|
||||
{
|
||||
PyObject *optype, *item;
|
||||
PyObject *base_class, *item;
|
||||
|
||||
|
||||
PyOperatorType *pyot;
|
||||
char *idname= NULL;
|
||||
char *name= NULL;
|
||||
char *description= NULL;
|
||||
|
||||
static char *pyop_func_names[] = {"exec", "invoke", "poll", NULL};
|
||||
static int pyop_func_nargs[] = {1, 2, 2, 0};
|
||||
|
||||
PyObject *pyargcount;
|
||||
int i, argcount;
|
||||
int i;
|
||||
|
||||
static struct BPY_class_attr_check pyop_class_attr_values[]= {
|
||||
{PYOP_ATTR_IDNAME, 's', 0, 0},
|
||||
{PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL},
|
||||
{PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL},
|
||||
{PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK},
|
||||
{"exec", 'f', 1, BPY_CLASS_ATTR_OPTIONAL},
|
||||
{"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
|
||||
{"poll", 'f', 2, 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");
|
||||
optype = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator");
|
||||
Py_DECREF(optype);
|
||||
base_class = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator");
|
||||
Py_DECREF(base_class);
|
||||
|
||||
|
||||
if (!PyObject_IsSubclass(value, optype)) {
|
||||
PyErr_SetString( PyExc_AttributeError, "expected Operator subclass of bpy.types.Operator");
|
||||
return NULL;
|
||||
if(BPY_class_validate("Operator", py_class, base_class, pyop_class_attr_values, NULL) < 0) {
|
||||
return NULL; /* BPY_class_validate sets the error */
|
||||
}
|
||||
|
||||
|
||||
/* class name is used for operator ID - this can be changed later if we want */
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_IDNAME);
|
||||
item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
|
||||
Py_DECREF(item);
|
||||
idname = _PyUnicode_AsString(item);
|
||||
|
||||
|
||||
if (WM_operatortype_find(idname)) {
|
||||
PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Operator user readible name */
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_UINAME);
|
||||
if (item) {
|
||||
Py_DECREF(item);
|
||||
name = _PyUnicode_AsString(item);
|
||||
}
|
||||
if (name == NULL) {
|
||||
name = idname;
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
/* use py docstring for description, should always be None or a string */
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_DESCRIPTION);
|
||||
Py_DECREF(item);
|
||||
|
||||
if (PyUnicode_Check(item)) {
|
||||
description = _PyUnicode_AsString(item);
|
||||
}
|
||||
else {
|
||||
description = "";
|
||||
}
|
||||
|
||||
/* Check known functions and argument lengths */
|
||||
for (i=0; pyop_func_names[i]; i++) {
|
||||
|
||||
item=PyObject_GetAttrString(value, pyop_func_names[i]);
|
||||
if (item) {
|
||||
Py_DECREF(item);
|
||||
|
||||
/* check its callable */
|
||||
if (!PyFunction_Check(item)) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() is not a function", idname, pyop_func_names[i]);
|
||||
return NULL;
|
||||
}
|
||||
/* check the number of args is correct */
|
||||
/* MyClass.exec.func_code.co_argcount */
|
||||
|
||||
pyargcount = PyObject_GetAttrString(PyFunction_GET_CODE(item), "co_argcount");
|
||||
Py_DECREF(pyargcount);
|
||||
argcount = PyLong_AsSsize_t(pyargcount);
|
||||
|
||||
if (argcount != pyop_func_nargs[i]) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() takes %d args, should be %d", idname, pyop_func_names[i], argcount, pyop_func_nargs[i]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have properties set, check its a list of dicts */
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_PROP);
|
||||
item= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP);
|
||||
if (item) {
|
||||
Py_DECREF(item);
|
||||
|
||||
if (!PyList_Check(item)) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.properties must be a list", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(i=0; i<PyList_Size(item); i++) {
|
||||
PyObject *py_args = PyList_GET_ITEM(item, i);
|
||||
PyObject *py_func_ptr, *py_kw; /* place holders */
|
||||
@@ -477,24 +430,18 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *value)
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
pyot= MEM_callocN(sizeof(PyOperatorType), "PyOperatorType");
|
||||
|
||||
strncpy(pyot->idname, idname, sizeof(pyot->idname));
|
||||
strncpy(pyot->name, name, sizeof(pyot->name));
|
||||
strncpy(pyot->description, description, sizeof(pyot->description));
|
||||
pyot->py_class= value;
|
||||
Py_INCREF(value);
|
||||
|
||||
WM_operatortype_append_ptr(PYTHON_OT_wrapper, pyot);
|
||||
Py_INCREF(py_class);
|
||||
WM_operatortype_append_ptr(PYTHON_OT_wrapper, py_class);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
|
||||
{
|
||||
PyObject *py_class;
|
||||
char *idname= NULL;
|
||||
wmOperatorType *ot;
|
||||
PyOperatorType *pyot;
|
||||
|
||||
|
||||
if (PyUnicode_Check(value))
|
||||
idname = _PyUnicode_AsString(value);
|
||||
@@ -514,13 +461,12 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pyot= (PyOperatorType *)ot->pyop_data)) {
|
||||
if (!(py_class= (PyObject *)ot->pyop_data)) {
|
||||
PyErr_Format( PyExc_AttributeError, "Operator \"%s\" was not created by python", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_XDECREF(pyot->py_class);
|
||||
MEM_freeN(pyot);
|
||||
Py_XDECREF(py_class);
|
||||
|
||||
WM_operatortype_remove(idname);
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
#ifndef BPY_OPWRAPPER_H
|
||||
#define BPY_OPWRAPPER_H
|
||||
#ifndef BPY_OPERATOR_WRAP_H
|
||||
#define BPY_OPERATOR_WRAP_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
36
source/blender/python/intern/bpy_panel_wrap.h
Normal file
36
source/blender/python/intern/bpy_panel_wrap.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
/**
|
||||
* $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 *****
|
||||
*/
|
||||
|
||||
#ifndef BPY_PANEL_WRAP_H
|
||||
#define BPY_PANEL_WRAP_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
/* these are used for operator methods, used by bpy_operator.c */
|
||||
|
||||
PyObject *PyPanel_wrap_add(PyObject *self, PyObject *args);
|
||||
PyObject *PyPanel_wrap_remove(PyObject *self, PyObject *args);
|
||||
|
||||
#endif
|
||||
@@ -128,20 +128,9 @@ static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
|
||||
{
|
||||
const EnumPropertyItem *item;
|
||||
int totitem, i;
|
||||
|
||||
DynStr *dynstr= BLI_dynstr_new();
|
||||
char *cstring;
|
||||
|
||||
RNA_property_enum_items(ptr, prop, &item, &totitem);
|
||||
|
||||
for (i=0; i<totitem; i++) {
|
||||
|
||||
BLI_dynstr_appendf(dynstr, i?", '%s'":"'%s'", item[i].identifier);
|
||||
}
|
||||
|
||||
cstring = BLI_dynstr_get_cstring(dynstr);
|
||||
BLI_dynstr_free(dynstr);
|
||||
return cstring;
|
||||
RNA_property_enum_items(ptr, prop, &item, &totitem);
|
||||
return BPy_enum_as_string(item);
|
||||
}
|
||||
|
||||
PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "bpy_rna.h" /* for rna buttons */
|
||||
#include "bpy_operator.h" /* for setting button operator properties */
|
||||
#include "bpy_compat.h"
|
||||
#include "bpy_panel_wrap.h" /* for setting button operator properties */
|
||||
|
||||
#include "WM_types.h" /* for WM_OP_INVOKE_DEFAULT & friends */
|
||||
|
||||
#include "BLI_dynstr.h"
|
||||
@@ -423,6 +425,10 @@ static struct PyMethodDef ui_methods[] = {
|
||||
{"getScreenPtr", (PyCFunction)Method_getScreenPtr, METH_NOARGS, ""},
|
||||
{"getSpacePtr", (PyCFunction)Method_getSpacePtr, METH_NOARGS, ""},
|
||||
{"getWindowPtr", (PyCFunction)Method_getWindowPtr, METH_NOARGS, ""},
|
||||
|
||||
/* Adding panels should be moved, at the moment there is no obvious place as there is with operators */
|
||||
{"addPanel", (PyCFunction)PyPanel_wrap_add, METH_VARARGS, ""},
|
||||
{"removePanel", (PyCFunction)PyPanel_wrap_remove, METH_VARARGS, ""},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "bpy_util.h"
|
||||
#include "BLI_dynstr.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "bpy_compat.h"
|
||||
|
||||
PyObject *BPY_flag_to_list(struct BPY_flag_def *flagdef, int flag)
|
||||
{
|
||||
@@ -241,3 +240,91 @@ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
|
||||
Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs)
|
||||
{
|
||||
PyObject *item;
|
||||
PyObject *py_arg_count;
|
||||
int i, arg_count;
|
||||
|
||||
if (base_class) {
|
||||
if (!PyObject_IsSubclass(class, base_class)) {
|
||||
PyObject *name= PyObject_GetAttrString(base_class, "__name__");
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s subclass of class \"%s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
|
||||
Py_XDECREF(name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for(i= 0;class_attrs->name; class_attrs++, i++) {
|
||||
item = PyObject_GetAttrString(class, class_attrs->name);
|
||||
|
||||
if (py_class_attrs)
|
||||
py_class_attrs[i]= item;
|
||||
|
||||
if (item==NULL) {
|
||||
if ((class_attrs->flag & BPY_CLASS_ATTR_OPTIONAL)==0) {
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, class_attrs->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
}
|
||||
else {
|
||||
Py_DECREF(item); /* no need to keep a ref, the class owns it */
|
||||
|
||||
if((item==Py_None) && (class_attrs->flag & BPY_CLASS_ATTR_NONE_OK)) {
|
||||
/* dont do anything, this is ok, dont bother checking other types */
|
||||
}
|
||||
else {
|
||||
switch(class_attrs->type) {
|
||||
case 's':
|
||||
if (PyUnicode_Check(item)==0) {
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a string", class_type, class_attrs->name);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (PyList_Check(item)==0) {
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a list", class_type, class_attrs->name);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (PyFunction_Check(item)==0) {
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a function", class_type, class_attrs->name);
|
||||
return -1;
|
||||
}
|
||||
if (class_attrs->arg_count >= 0) { /* -1 if we dont care*/
|
||||
py_arg_count = PyObject_GetAttrString(PyFunction_GET_CODE(item), "co_argcount");
|
||||
arg_count = PyLong_AsSsize_t(py_arg_count);
|
||||
Py_DECREF(py_arg_count);
|
||||
|
||||
if (arg_count != class_attrs->arg_count) {
|
||||
PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, class_attrs->name, class_attrs->arg_count);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *BPy_enum_as_string(EnumPropertyItem *item)
|
||||
{
|
||||
DynStr *dynstr= BLI_dynstr_new();
|
||||
EnumPropertyItem *e;
|
||||
char *cstring;
|
||||
|
||||
for (e= item; item->identifier; item++) {
|
||||
BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier);
|
||||
}
|
||||
|
||||
cstring = BLI_dynstr_get_cstring(dynstr);
|
||||
BLI_dynstr_free(dynstr);
|
||||
return cstring;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#define BPY_UTIL_H
|
||||
|
||||
#include "bpy_compat.h"
|
||||
#include "RNA_types.h" /* for EnumPropertyItem only */
|
||||
|
||||
struct EnumPropertyItem;
|
||||
|
||||
/* for internal use only, so python can interchange a sequence of strings with flags */
|
||||
typedef struct BPY_flag_def {
|
||||
@@ -46,4 +49,22 @@ void BPY_getFileAndNum(char **filename, int *lineno);
|
||||
/* own python like utility function */
|
||||
PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
|
||||
|
||||
|
||||
|
||||
/* Class type checking, use for checking classes can be added as operators, panels etc */
|
||||
typedef struct BPY_class_attr_check {
|
||||
const char *name; /* name of the class attribute */
|
||||
char type; /* 's' = string, 'f' = function, 'l' = list, (add as needed) */
|
||||
int arg_count; /* only for function types, -1 for undefined, includes self arg */
|
||||
int flag; /* other options */
|
||||
} BPY_class_attr_check;
|
||||
|
||||
/* BPY_class_attr_check, flag */
|
||||
#define BPY_CLASS_ATTR_OPTIONAL 1
|
||||
#define BPY_CLASS_ATTR_NONE_OK 2
|
||||
|
||||
int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs);
|
||||
|
||||
char *BPy_enum_as_string(struct EnumPropertyItem *item);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user