forked from bartvdbraak/blender
support for dynamic items in bpy.props.EnumProperty(), the items keyword argument can optionally be a function rather then a list.
This commit is contained in:
parent
155d589333
commit
57c3c9e70f
@ -743,6 +743,7 @@ int RNA_property_string_default_length(PointerRNA *ptr, PropertyRNA *prop);
|
|||||||
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
|
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
|
||||||
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
|
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
|
||||||
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
|
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
|
||||||
|
void *RNA_property_enum_py_data_get(PropertyRNA *prop);
|
||||||
|
|
||||||
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
|
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
|
||||||
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
|
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
|
||||||
|
@ -90,6 +90,7 @@ PropertyRNA *RNA_def_string_file_name(StructOrFunctionRNA *cont, const char *ide
|
|||||||
PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description);
|
PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description);
|
||||||
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description);
|
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description);
|
||||||
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc);
|
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc);
|
||||||
|
void RNA_def_enum_py_data(PropertyRNA *prop, void *py_data);
|
||||||
|
|
||||||
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
|
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
|
||||||
PropertyRNA *RNA_def_float_vector(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
|
PropertyRNA *RNA_def_float_vector(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
|
||||||
|
@ -2223,7 +2223,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
|
|||||||
}
|
}
|
||||||
case PROP_ENUM: {
|
case PROP_ENUM: {
|
||||||
EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
|
EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
|
||||||
fprintf(f, "\t%s, %s, %s, ", rna_function_string(eprop->get), rna_function_string(eprop->set), rna_function_string(eprop->itemf));
|
fprintf(f, "\t%s, %s, %s, NULL, ", rna_function_string(eprop->get), rna_function_string(eprop->set), rna_function_string(eprop->itemf));
|
||||||
if(eprop->item)
|
if(eprop->item)
|
||||||
fprintf(f, "rna_%s%s_%s_items, ", srna->identifier, strnest, prop->identifier);
|
fprintf(f, "rna_%s%s_%s_items, ", srna->identifier, strnest, prop->identifier);
|
||||||
else
|
else
|
||||||
|
@ -2120,6 +2120,14 @@ int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop)
|
|||||||
return eprop->defaultvalue;
|
return eprop->defaultvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *RNA_property_enum_py_data_get(PropertyRNA *prop)
|
||||||
|
{
|
||||||
|
EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
|
||||||
|
|
||||||
|
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
|
||||||
|
|
||||||
|
return eprop->py_data;
|
||||||
|
}
|
||||||
|
|
||||||
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
|
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
|
||||||
{
|
{
|
||||||
|
@ -2276,6 +2276,12 @@ void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
|
|||||||
eprop->itemf= itemfunc;
|
eprop->itemf= itemfunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RNA_def_enum_py_data(PropertyRNA *prop, void *py_data)
|
||||||
|
{
|
||||||
|
EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop;
|
||||||
|
eprop->py_data= py_data;
|
||||||
|
}
|
||||||
|
|
||||||
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value,
|
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value,
|
||||||
float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
|
float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
|
||||||
{
|
{
|
||||||
|
@ -251,6 +251,7 @@ typedef struct EnumPropertyRNA {
|
|||||||
PropEnumGetFunc get;
|
PropEnumGetFunc get;
|
||||||
PropEnumSetFunc set;
|
PropEnumSetFunc set;
|
||||||
PropEnumItemFunc itemf;
|
PropEnumItemFunc itemf;
|
||||||
|
void *py_data; /* store py callback here */
|
||||||
|
|
||||||
EnumPropertyItem *item;
|
EnumPropertyItem *item;
|
||||||
int totitem;
|
int totitem;
|
||||||
|
@ -47,6 +47,8 @@
|
|||||||
|
|
||||||
#include "../generic/py_capi_utils.h"
|
#include "../generic/py_capi_utils.h"
|
||||||
|
|
||||||
|
extern BPy_StructRNA *bpy_context_module;
|
||||||
|
|
||||||
static EnumPropertyItem property_flag_items[]= {
|
static EnumPropertyItem property_flag_items[]= {
|
||||||
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
|
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
|
||||||
{PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""},
|
{PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""},
|
||||||
@ -741,6 +743,95 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EnumPropertyItem *bpy_props_enum_itemf(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int *free)
|
||||||
|
{
|
||||||
|
PyGILState_STATE gilstate;
|
||||||
|
|
||||||
|
PyObject *py_func= RNA_property_enum_py_data_get(prop);
|
||||||
|
PyObject *self= NULL;
|
||||||
|
PyObject *args;
|
||||||
|
PyObject *items; /* returned from the function call */
|
||||||
|
|
||||||
|
EnumPropertyItem *eitems= NULL;
|
||||||
|
int err= 0;
|
||||||
|
|
||||||
|
bpy_context_set(C, &gilstate);
|
||||||
|
|
||||||
|
args= PyTuple_New(2);
|
||||||
|
|
||||||
|
/* first get self */
|
||||||
|
/* operators can store their own instance for later use */
|
||||||
|
if(ptr->data) {
|
||||||
|
void **instance = RNA_struct_instance(ptr);
|
||||||
|
|
||||||
|
if(instance) {
|
||||||
|
if(*instance) {
|
||||||
|
self= *instance;
|
||||||
|
Py_INCREF(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(self == NULL) {
|
||||||
|
self= pyrna_struct_CreatePyObject(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyTuple_SET_ITEM(args, 0, self);
|
||||||
|
|
||||||
|
/* now get the context */
|
||||||
|
PyTuple_SET_ITEM(args, 1, (PyObject *)bpy_context_module);
|
||||||
|
Py_INCREF(bpy_context_module);
|
||||||
|
|
||||||
|
items= PyObject_CallObject(py_func, args);
|
||||||
|
|
||||||
|
Py_DECREF(args);
|
||||||
|
|
||||||
|
if(items==NULL) {
|
||||||
|
err= -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject *items_fast;
|
||||||
|
int defvalue_dummy=0;
|
||||||
|
|
||||||
|
if(!(items_fast= PySequence_Fast(items, "EnumProperty(...): return value from the callback was not a sequence"))) {
|
||||||
|
err= -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eitems= enum_items_from_py(items_fast, NULL, &defvalue_dummy, (RNA_property_flag(prop) & PROP_ENUM_FLAG)!=0);
|
||||||
|
|
||||||
|
Py_DECREF(items_fast);
|
||||||
|
|
||||||
|
if(!eitems) {
|
||||||
|
err= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err != -1) { /* worked */
|
||||||
|
*free= 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* since we return to C code we can't leave the error */
|
||||||
|
PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(py_func);
|
||||||
|
PyErr_Print();
|
||||||
|
PyErr_Clear();
|
||||||
|
|
||||||
|
/* use py style error */
|
||||||
|
fprintf(stderr, "File \"%s\", line %d, in %s\n",
|
||||||
|
_PyUnicode_AsString(f_code->co_filename),
|
||||||
|
f_code->co_firstlineno,
|
||||||
|
_PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
eitems= DummyRNA_NULL_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bpy_context_clear(C, &gilstate);
|
||||||
|
return eitems;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(BPy_EnumProperty_doc,
|
PyDoc_STRVAR(BPy_EnumProperty_doc,
|
||||||
".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n"
|
".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", options={'ANIMATABLE'})\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -752,8 +843,8 @@ BPY_PROPDEF_DESC_DOC
|
|||||||
" :type default: string or set\n"
|
" :type default: string or set\n"
|
||||||
" :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE', 'ENUM_FLAG'].\n"
|
" :arg options: Enumerator in ['HIDDEN', 'ANIMATABLE', 'ENUM_FLAG'].\n"
|
||||||
" :type options: set\n"
|
" :type options: set\n"
|
||||||
" :arg items: sequence of enum items formatted: [(identifier, name, description), ...] where the identifier is used for python access and other values are used for the interface.\n"
|
" :arg items: sequence of enum items formatted: [(identifier, name, description), ...] where the identifier is used for python access and other values are used for the interface. For dynamic values a callback can be passed which returns a list in the format described, taking 2 arguments - self and context argument\n"
|
||||||
" :type items: sequence of string triplets\n"
|
" :type items: sequence of string triplets or a function\n"
|
||||||
);
|
);
|
||||||
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
|
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
@ -772,6 +863,7 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
|
|||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
PyObject *pyopts= NULL;
|
PyObject *pyopts= NULL;
|
||||||
int opts=0;
|
int opts=0;
|
||||||
|
short is_itemf= FALSE;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw,
|
if (!PyArg_ParseTupleAndKeywords(args, kw,
|
||||||
"s#O|ssOO!:EnumProperty",
|
"s#O|ssOO!:EnumProperty",
|
||||||
@ -784,26 +876,58 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
|
|||||||
|
|
||||||
BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items)
|
BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items)
|
||||||
|
|
||||||
if(!(items_fast= PySequence_Fast(items, "EnumProperty(...): expected a sequence of tuples for the enum items"))) {
|
/* items can be a list or a callable */
|
||||||
return NULL;
|
if(PyFunction_Check(items)) { /* dont use PyCallable_Check because we need the function code for errors */
|
||||||
|
PyCodeObject *f_code= (PyCodeObject *)PyFunction_GET_CODE(items);
|
||||||
|
if(f_code->co_argcount != 2) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"EnumProperty(...): expected 'items' function to take 2 arguments, not %d",
|
||||||
|
f_code->co_argcount);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(def) {
|
||||||
|
/* note, using type error here is odd but python does this for invalid arguments */
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"EnumProperty(...): 'default' can't be set when 'items' is a function");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_itemf= TRUE;
|
||||||
|
eitems= DummyRNA_NULL_items;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if(!(items_fast= PySequence_Fast(items, "EnumProperty(...): expected a sequence of tuples for the enum items or a function"))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
eitems= enum_items_from_py(items_fast, def, &defvalue, (opts & PROP_ENUM_FLAG)!=0);
|
eitems= enum_items_from_py(items_fast, def, &defvalue, (opts & PROP_ENUM_FLAG)!=0);
|
||||||
|
|
||||||
Py_DECREF(items_fast);
|
Py_DECREF(items_fast);
|
||||||
|
|
||||||
if(!eitems)
|
if(!eitems) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(opts & PROP_ENUM_FLAG) prop= RNA_def_enum_flag(srna, id, eitems, defvalue, name, description);
|
if(opts & PROP_ENUM_FLAG) prop= RNA_def_enum_flag(srna, id, eitems, defvalue, name, description);
|
||||||
else prop= RNA_def_enum(srna, id, eitems, defvalue, name, description);
|
else prop= RNA_def_enum(srna, id, eitems, defvalue, name, description);
|
||||||
|
|
||||||
|
if(is_itemf) {
|
||||||
|
RNA_def_enum_funcs(prop, bpy_props_enum_itemf);
|
||||||
|
RNA_def_enum_py_data(prop, (void *)items);
|
||||||
|
/* Py_INCREF(items); */ /* watch out!, if user is tricky they can probably crash blender if they manage to free the callback, take care! */
|
||||||
|
}
|
||||||
|
|
||||||
if(pyopts) {
|
if(pyopts) {
|
||||||
if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
|
if(opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||||
if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
if((opts & PROP_ANIMATABLE)==0) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
}
|
}
|
||||||
RNA_def_property_duplicate_pointers(srna, prop);
|
RNA_def_property_duplicate_pointers(srna, prop);
|
||||||
MEM_freeN(eitems);
|
|
||||||
|
if(is_itemf == FALSE) {
|
||||||
|
MEM_freeN(eitems);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user