diff options
Diffstat (limited to 'source/blender/python/intern/bpy_props.c')
-rw-r--r-- | source/blender/python/intern/bpy_props.c | 2640 |
1 files changed, 1525 insertions, 1115 deletions
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 14e25e02d84..a84d920d47d 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -492,6 +492,145 @@ static void bpy_prop_assign_flag_override(PropertyRNA *prop, const int flag_over /** \} */ /* -------------------------------------------------------------------- */ +/** \name Multi-Dimensional Property Utilities + * \{ */ + +struct BPyPropArrayLength { + int len_total; + /** Ignore `dims` when `dims_len == 0`. */ + int dims[RNA_MAX_ARRAY_DIMENSION]; + int dims_len; +}; + +/** + * Use with #PyArg_ParseTuple's `O&` formatting. + */ +static int bpy_prop_array_length_parse(PyObject *o, void *p) +{ + struct BPyPropArrayLength *array_len_info = p; + + if (PyLong_CheckExact(o)) { + int size; + if (((size = PyLong_AsLong(o)) == -1)) { + PyErr_Format( + PyExc_ValueError, "expected number or sequence of numbers, got %s", Py_TYPE(o)->tp_name); + return 0; + } + if (size < 1 || size > PYRNA_STACK_ARRAY) { + PyErr_Format( + PyExc_TypeError, "(size=%d) must be between 1 and " STRINGIFY(PYRNA_STACK_ARRAY), size); + return 0; + } + array_len_info->len_total = size; + + /* Don't use this value. */ + array_len_info->dims_len = 0; + } + else { + PyObject *seq_fast; + if (!(seq_fast = PySequence_Fast(o, "size must be a number of a sequence of numbers"))) { + return 0; + } + const int seq_len = PySequence_Fast_GET_SIZE(seq_fast); + if (seq_len < 1 || seq_len > RNA_MAX_ARRAY_DIMENSION) { + PyErr_Format( + PyExc_TypeError, + "(len(size)=%d) length must be between 1 and " STRINGIFY(RNA_MAX_ARRAY_DIMENSION), + seq_len); + Py_DECREF(seq_fast); + return 0; + } + + PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); + for (int i = 0; i < seq_len; i++) { + int size; + if (((size = PyLong_AsLong(seq_items[i])) == -1)) { + Py_DECREF(seq_fast); + PyErr_Format(PyExc_ValueError, + "expected number in sequence, got %s at index %d", + Py_TYPE(o)->tp_name, + i); + return 0; + } + if (size < 1 || size > PYRNA_STACK_ARRAY) { + Py_DECREF(seq_fast); + PyErr_Format(PyExc_TypeError, + "(size[%d]=%d) must be between 1 and " STRINGIFY(PYRNA_STACK_ARRAY), + i, + size); + return 0; + } + + array_len_info->dims[i] = size; + array_len_info->dims_len = seq_len; + } + } + return 1; +} + +/** + * Return -1 on error. + */ +static int bpy_prop_array_from_py_with_dims(void *values, + size_t values_elem_size, + PyObject *py_values, + const struct BPyPropArrayLength *array_len_info, + const PyTypeObject *type, + const char *error_str) +{ + if (array_len_info->dims_len == 0) { + return PyC_AsArray( + values, values_elem_size, py_values, array_len_info->len_total, type, error_str); + } + const int *dims = array_len_info->dims; + const int dims_len = array_len_info->dims_len; + return PyC_AsArray_Multi(values, values_elem_size, py_values, dims, dims_len, type, error_str); +} + +static bool bpy_prop_array_is_matrix_compatible_ex(int subtype, + const struct BPyPropArrayLength *array_len_info) +{ + return ((subtype == PROP_MATRIX) && (array_len_info->dims_len == 2) && + ((array_len_info->dims[0] >= 2) && (array_len_info->dims[0] >= 4)) && + ((array_len_info->dims[1] >= 2) && (array_len_info->dims[1] >= 4))); +} + +static bool bpy_prop_array_is_matrix_compatible(PropertyRNA *prop, + const struct BPyPropArrayLength *array_len_info) +{ + BLI_assert(RNA_property_type(prop) == PROP_FLOAT); + return bpy_prop_array_is_matrix_compatible_ex(RNA_property_subtype(prop), array_len_info); +} + +/** + * Needed since the internal storage of matrices swaps row/column. + */ +static void bpy_prop_array_matrix_swap_row_column_vn_vn( + float *values_dst, const float *values_src, const struct BPyPropArrayLength *array_len_info) +{ + BLI_assert(values_dst != values_src); + const int dim0 = array_len_info->dims[0], dim1 = array_len_info->dims[1]; + BLI_assert(dim0 <= 4 && dim1 <= 4); + for (int i = 0; i < dim0; i++) { + for (int j = 0; j < dim1; j++) { + values_dst[(j * dim0) + i] = values_src[(i * dim1) + j]; + } + } +} + +static void bpy_prop_array_matrix_swap_row_column_vn( + float *values, const struct BPyPropArrayLength *array_len_info) +{ + const int dim0 = array_len_info->dims[0], dim1 = array_len_info->dims[1]; + BLI_assert(dim0 <= 4 && dim1 <= 4); + float values_orig[4 * 4]; + memcpy(values_orig, values, sizeof(float) * (dim0 * dim1)); + bpy_prop_array_matrix_swap_row_column_vn_vn(values, values_orig, array_len_info); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Shared Property Callbacks * * Unique data is accessed via #RNA_property_py_data_get @@ -687,7 +826,10 @@ static void bpy_prop_boolean_array_get_fn(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); + bool is_values_set = false; int i, len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -711,25 +853,25 @@ static void bpy_prop_boolean_array_get_fn(struct PointerRNA *ptr, Py_DECREF(args); - if (ret == NULL) { - PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = false; - } - } - else { - if (PyC_AsArray(values, ret, len, &PyBool_Type, false, "BoolVectorProperty get") == -1) { + if (ret != NULL) { + if (bpy_prop_array_from_py_with_dims(values, + sizeof(*values), + ret, + &array_len_info, + &PyBool_Type, + "BoolVectorProperty get callback") == -1) { PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = false; - } - - /* PyC_AsArray decrements refcount internally on error */ } else { - Py_DECREF(ret); + is_values_set = true; + } + Py_DECREF(ret); + } + + if (is_values_set == false) { + /* This is the flattened length for multi-dimensional arrays. */ + for (i = 0; i < len; i++) { + values[i] = false; } } @@ -756,6 +898,8 @@ static void bpy_prop_boolean_array_set_fn(struct PointerRNA *ptr, bool use_gil; const bool is_write_ok = pyrna_write_check(); const int len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -775,7 +919,13 @@ static void bpy_prop_boolean_array_set_fn(struct PointerRNA *ptr, self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_Tuple_PackArray_Bool(values, len); + if (array_len_info.dims_len == 0) { + py_values = PyC_Tuple_PackArray_Bool(values, len); + } + else { + py_values = PyC_Tuple_PackArray_Multi_Bool( + values, array_len_info.dims, array_len_info.dims_len); + } PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -937,7 +1087,10 @@ static void bpy_prop_int_array_get_fn(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); + bool is_values_set = false; int i, len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -961,25 +1114,25 @@ static void bpy_prop_int_array_get_fn(struct PointerRNA *ptr, Py_DECREF(args); - if (ret == NULL) { - PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = 0; - } - } - else { - if (PyC_AsArray(values, ret, len, &PyLong_Type, false, "IntVectorProperty get") == -1) { + if (ret != NULL) { + if (bpy_prop_array_from_py_with_dims(values, + sizeof(*values), + ret, + &array_len_info, + &PyLong_Type, + "IntVectorProperty get callback") == -1) { PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = 0; - } - - /* PyC_AsArray decrements refcount internally on error */ } else { - Py_DECREF(ret); + is_values_set = true; + } + Py_DECREF(ret); + } + + if (is_values_set == false) { + /* This is the flattened length for multi-dimensional arrays. */ + for (i = 0; i < len; i++) { + values[i] = 0; } } @@ -1006,6 +1159,8 @@ static void bpy_prop_int_array_set_fn(struct PointerRNA *ptr, bool use_gil; const bool is_write_ok = pyrna_write_check(); const int len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -1025,7 +1180,14 @@ static void bpy_prop_int_array_set_fn(struct PointerRNA *ptr, self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_Tuple_PackArray_I32(values, len); + if (array_len_info.dims_len == 0) { + py_values = PyC_Tuple_PackArray_I32(values, len); + } + else { + py_values = PyC_Tuple_PackArray_Multi_I32( + values, array_len_info.dims, array_len_info.dims_len); + } + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -1187,7 +1349,10 @@ static void bpy_prop_float_array_get_fn(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); + bool is_values_set = false; int i, len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -1211,25 +1376,29 @@ static void bpy_prop_float_array_get_fn(struct PointerRNA *ptr, Py_DECREF(args); - if (ret == NULL) { - PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = 0.0f; - } - } - else { - if (PyC_AsArray(values, ret, len, &PyFloat_Type, false, "FloatVectorProperty get") == -1) { + if (ret != NULL) { + if (bpy_prop_array_from_py_with_dims(values, + sizeof(*values), + ret, + &array_len_info, + &PyFloat_Type, + "FloatVectorProperty get callback") == -1) { PyC_Err_PrintWithFunc(py_func); - - for (i = 0; i < len; i++) { - values[i] = 0.0f; - } - - /* PyC_AsArray decrements refcount internally on error */ } else { - Py_DECREF(ret); + /* Only for float types. */ + if (bpy_prop_array_is_matrix_compatible(prop, &array_len_info)) { + bpy_prop_array_matrix_swap_row_column_vn(values, &array_len_info); + } + is_values_set = true; + } + Py_DECREF(ret); + } + + if (is_values_set == false) { + /* This is the flattened length for multi-dimensional arrays. */ + for (i = 0; i < len; i++) { + values[i] = 0.0f; } } @@ -1256,6 +1425,8 @@ static void bpy_prop_float_array_set_fn(struct PointerRNA *ptr, bool use_gil; const bool is_write_ok = pyrna_write_check(); const int len = RNA_property_array_length(ptr, prop); + struct BPyPropArrayLength array_len_info = {.len_total = len}; + array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims); BLI_assert(prop_store != NULL); @@ -1275,7 +1446,14 @@ static void bpy_prop_float_array_set_fn(struct PointerRNA *ptr, self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_Tuple_PackArray_F32(values, len); + if (array_len_info.dims_len == 0) { + py_values = PyC_Tuple_PackArray_F32(values, len); + } + else { + /* No need for matrix column/row swapping here unless the matrix data is read directly. */ + py_values = PyC_Tuple_PackArray_Multi_F32( + values, array_len_info.dims, array_len_info.dims_len); + } PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -1720,9 +1898,9 @@ static int icon_id_from_name(const char *name) } static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, - PyObject *def, - int *defvalue, - const bool is_enum_flag) + const bool is_enum_flag, + PyObject *default_py, + int *r_default_value) { EnumPropertyItem *items; PyObject *item; @@ -1730,9 +1908,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast); Py_ssize_t totbuf = 0; int i; - short def_used = 0; - const char *def_string_cmp = NULL; - int def_int_cmp = 0; + short default_used = 0; + const char *default_str_cmp = NULL; + int default_int_cmp = 0; if (is_enum_flag) { if (seq_len > RNA_ENUM_BITFLAG_SIZE) { @@ -1741,23 +1919,23 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, RNA_ENUM_BITFLAG_SIZE) " members for a ENUM_FLAG type property"); return NULL; } - if (def && !PySet_Check(def)) { + if (default_py && !PySet_Check(default_py)) { PyErr_Format(PyExc_TypeError, "EnumProperty(...): default option must be a 'set' " "type when ENUM_FLAG is enabled, not a '%.200s'", - Py_TYPE(def)->tp_name); + Py_TYPE(default_py)->tp_name); return NULL; } } else { - if (def) { - if (!py_long_as_int(def, &def_int_cmp)) { - def_string_cmp = PyUnicode_AsUTF8(def); - if (def_string_cmp == NULL) { + if (default_py) { + if (!py_long_as_int(default_py, &default_int_cmp)) { + default_str_cmp = PyUnicode_AsUTF8(default_py); + if (default_str_cmp == NULL) { PyErr_Format(PyExc_TypeError, "EnumProperty(...): default option must be a 'str' or 'int' " "type when ENUM_FLAG is disabled, not a '%.200s'", - Py_TYPE(def)->tp_name); + Py_TYPE(default_py)->tp_name); return NULL; } } @@ -1765,7 +1943,7 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, } /* blank value */ - *defvalue = 0; + *r_default_value = 0; items = MEM_callocN(sizeof(EnumPropertyItem) * (seq_len + 1), "enum_items_from_py1"); @@ -1779,7 +1957,7 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, item = seq_fast_items[i]; - if ((PyTuple_CheckExact(item)) && (item_size = PyTuple_GET_SIZE(item)) && + if (PyTuple_CheckExact(item) && (item_size = PyTuple_GET_SIZE(item)) && (item_size >= 3 && item_size <= 5) && (tmp.identifier = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(item, 0), &id_str_size)) && (tmp.name = PyUnicode_AsUTF8AndSize(PyTuple_GET_ITEM(item, 1), &name_str_size)) && @@ -1794,9 +1972,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, tmp.value = 1 << i; } - if (def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) { - *defvalue |= tmp.value; - def_used++; + if (default_py && PySet_Contains(default_py, PyTuple_GET_ITEM(item, 0))) { + *r_default_value |= tmp.value; + default_used++; } } else { @@ -1804,11 +1982,11 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, tmp.value = i; } - if (def && def_used == 0) { - if ((def_string_cmp != NULL && STREQ(def_string_cmp, tmp.identifier)) || - (def_string_cmp == NULL && def_int_cmp == tmp.value)) { - *defvalue = tmp.value; - def_used++; /* only ever 1 */ + if (default_py && default_used == 0) { + if ((default_str_cmp != NULL && STREQ(default_str_cmp, tmp.identifier)) || + (default_str_cmp == NULL && default_int_cmp == tmp.value)) { + *r_default_value = tmp.value; + default_used++; /* only ever 1 */ } } } @@ -1838,28 +2016,28 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, if (is_enum_flag) { /* strict check that all set members were used */ - if (def && def_used != PySet_GET_SIZE(def)) { + if (default_py && default_used != PySet_GET_SIZE(default_py)) { MEM_freeN(items); PyErr_Format(PyExc_TypeError, "EnumProperty(..., default={...}): set has %d unused member(s)", - PySet_GET_SIZE(def) - def_used); + PySet_GET_SIZE(default_py) - default_used); return NULL; } } else { - if (def && def_used == 0) { + if (default_py && default_used == 0) { MEM_freeN(items); - if (def_string_cmp) { + if (default_str_cmp) { PyErr_Format(PyExc_TypeError, "EnumProperty(..., default=\'%s\'): not found in enum members", - def_string_cmp); + default_str_cmp); } else { PyErr_Format(PyExc_TypeError, "EnumProperty(..., default=%d): not found in enum members", - def_int_cmp); + default_int_cmp); } return NULL; } @@ -1938,7 +2116,7 @@ static const EnumPropertyItem *bpy_prop_enum_itemf_fn(struct bContext *C, } else { PyObject *items_fast; - int defvalue_dummy = 0; + int default_value_dummy = 0; if (!(items_fast = PySequence_Fast(items, "EnumProperty(...): " @@ -1947,7 +2125,7 @@ static const EnumPropertyItem *bpy_prop_enum_itemf_fn(struct bContext *C, } else { eitems = enum_items_from_py( - items_fast, NULL, &defvalue_dummy, (RNA_property_flag(prop) & PROP_ENUM_FLAG) != 0); + items_fast, (RNA_property_flag(prop) & PROP_ENUM_FLAG) != 0, NULL, &default_value_dummy); Py_DECREF(items_fast); @@ -2240,84 +2418,141 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, /** \name Shared Method Utilities * \{ */ -/* this define runs at the start of each function and deals with - * returning a deferred property (to be registered later) */ -#define BPY_PROPDEF_HEAD(_func) \ - if (PyTuple_GET_SIZE(args) == 1) { \ - PyObject *ret; \ - self = PyTuple_GET_ITEM(args, 0); \ - args = PyTuple_New(0); \ - ret = BPy_##_func(self, args, kw); \ - Py_DECREF(args); \ - return ret; \ - } \ - if (PyTuple_GET_SIZE(args) > 1) { \ - PyErr_SetString(PyExc_ValueError, "all args must be keywords"); \ - return NULL; \ - } \ - srna = srna_from_self(self, #_func "(...):"); \ - if (srna == NULL) { \ - if (PyErr_Occurred()) { \ - return NULL; \ - } \ - return bpy_prop_deferred_data_CreatePyObject(pymeth_##_func, kw); \ - } \ - (void)0 - -/* terse macros for error checks shared between all funcs can't use function - * calls because of static strings passed to pyrna_set_to_enum_bitfield */ -#define BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items) \ - if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) { \ - PyErr_Format(PyExc_TypeError, \ - #_func "(): '%.200s' too long, max length is %d", \ - id, \ - MAX_IDPROP_NAME - 1); \ - return NULL; \ - } \ - if (UNLIKELY(RNA_def_property_free_identifier(srna, id) == -1)) { \ - PyErr_Format(PyExc_TypeError, #_func "(): '%s' is defined as a non-dynamic type", id); \ - return NULL; \ - } \ - if (UNLIKELY(pyopts && pyrna_set_to_enum_bitfield( \ - _property_flag_items, pyopts, &opts, #_func "(options={ ...}):"))) { \ - return NULL; \ - } \ - if (UNLIKELY(pyopts_override && pyrna_set_to_enum_bitfield(_property_flag_override_items, \ - pyopts_override, \ - &opts_override, \ - #_func "(override={ ...}):"))) { \ - return NULL; \ - } \ - { \ - const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna); \ - if (py_tags && !tag_defines) { \ - PyErr_Format(PyExc_TypeError, \ - #_func "(): property-tags not available for '%s'", \ - RNA_struct_identifier(srna)); \ - return NULL; \ - } \ - if (UNLIKELY(py_tags && pyrna_set_to_enum_bitfield( \ - tag_defines, py_tags, &prop_tags, #_func "(tags={ ...}):"))) { \ - return NULL; \ - } \ - } \ - (void)0 - -#define BPY_PROPDEF_SUBTYPE_CHECK( \ - _func, _property_flag_items, _property_flag_override_items, _subtype) \ - BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items); \ - if (UNLIKELY(pysubtype && RNA_enum_value_from_id(_subtype, pysubtype, &subtype) == 0)) { \ - const char *enum_str = BPy_enum_as_string(_subtype); \ - PyErr_Format(PyExc_TypeError, \ - #_func \ - "(subtype='%s'): " \ - "subtype not found in (%s)", \ - pysubtype, \ - enum_str); \ - MEM_freeN((void *)enum_str); \ - return NULL; \ - } \ - (void)0 +/** + * This define runs at the start of each function and deals with + * returning a deferred property #BPy_PropDeferred (to be registered later). + * + * \param self: The self argument from the caller. + * \param args: The positional arguments of the caller. + * \param kw: The keyword arguments of the caller. + * \param method_object: The method of the caller (unfortunately this can't be deduced). + * \param r_deferred_result: The deferred result (or NULL in the case of an error). + * The caller must return this value unless a valid `srna` is returned. + * + * \returns When not null, the caller is expected to perform the registration. + */ +static StructRNA *bpy_prop_deferred_data_or_srna(PyObject *self, + PyObject *args, + PyObject *kw, + PyObject *method_object, + PyObject **r_deferred_result) +{ + /* This must be the methods of one of the main property types defined in this file. */ + BLI_assert(PyCFunction_CheckExact(method_object)); + + const int args_len = PyTuple_GET_SIZE(args); + PyMethodDef *method_def = ((PyCFunctionObject *)method_object)->m_ml; + + /* Call this function with the first argument set to `self`. */ + if (args_len == 1) { + self = PyTuple_GET_ITEM(args, 0); + args = PyTuple_New(0); + + /* This will be #BPy_BoolProperty` or one of the functions that define a type. */ + PyCFunctionWithKeywords method_fn = (PyCFunctionWithKeywords)method_def->ml_meth; + *r_deferred_result = method_fn(self, args, kw); + Py_DECREF(args); + /* May be an error (depending on `r_deferred_result`). */ + return NULL; + } + + const char *error_prefix = method_def->ml_name; + if (args_len > 1) { + PyErr_Format(PyExc_ValueError, "%s: all args must be keywords", error_prefix); + *r_deferred_result = NULL; + /* An error. */ + return NULL; + } + + StructRNA *srna = srna_from_self(self, error_prefix); + if (srna == NULL) { + *r_deferred_result = PyErr_Occurred() ? + NULL : + bpy_prop_deferred_data_CreatePyObject(method_object, kw); + /* May be an error (depending on `r_deferred_result`). */ + return NULL; + } + + /* Crash if this is ever used by accident! */ +#ifndef NDEBUG + *r_deferred_result = (PyObject *)(intptr_t)1; +#endif + + /* No error or deferred result, perform registration immediately. */ + return srna; +} + +struct BPy_PropIDParse { + const char *value; + StructRNA *srna; + /** + * In the case registering this properly replaces an existing dynamic property. + * Store a handle to the property for removal. + * This is needed so the property removal is deferred until all other arguments + * have been validated, otherwise failure elsewhere could leave the property un-registered. + */ + void *prop_free_handle; +}; + +/** + * Use with #PyArg_ParseTuple's `O&` formatting. + */ +static int bpy_prop_arg_parse_id(PyObject *o, void *p) +{ + struct BPy_PropIDParse *parse_data = p; + StructRNA *srna = parse_data->srna; + + if (!PyUnicode_Check(o)) { + PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name); + return 0; + } + + Py_ssize_t id_len; + const char *id; + + id = PyUnicode_AsUTF8AndSize(o, &id_len); + if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) { + PyErr_Format(PyExc_TypeError, "'%.200s' too long, max length is %d", id, MAX_IDPROP_NAME - 1); + return 0; + } + + parse_data->prop_free_handle = NULL; + if (UNLIKELY(RNA_def_property_free_identifier_deferred_prepare( + srna, id, &parse_data->prop_free_handle) == -1)) { + PyErr_Format(PyExc_TypeError, + "'%s' is defined as a non-dynamic type for '%s'", + id, + RNA_struct_identifier(srna)); + return 0; + } + parse_data->value = id; + return 1; +} + +/** + * Needed so #RNA_struct_property_tag_defines can be called on the `srna`. + */ +struct BPy_EnumProperty_Parse_WithSRNA { + struct BPy_EnumProperty_Parse base; + StructRNA *srna; +}; + +/** + * Wrapper for #pyrna_enum_bitfield_parse_set + * that looks up tags from the `srna`. + */ +static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p) +{ + struct BPy_EnumProperty_Parse_WithSRNA *parse_data = p; + parse_data->base.items = RNA_struct_property_tag_defines(parse_data->srna); + if (parse_data->base.items == NULL) { + PyErr_Format(PyExc_TypeError, + "property-tags not available for '%s'", + RNA_struct_identifier(parse_data->srna)); + return 0; + } + return pyrna_enum_bitfield_parse_set(o, &parse_data->base); +} /** \} */ @@ -2355,8 +2590,9 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, "value in the UI.\n" #define BPY_PROPDEF_VECSIZE_DOC \ - " :arg size: Vector dimensions in [1, " STRINGIFY(PYRNA_STACK_ARRAY) "].\n" \ -" :type size: int\n" + " :arg size: Vector dimensions in [1, " STRINGIFY(PYRNA_STACK_ARRAY) "]. " \ +"An int sequence can be used to define multi-dimension arrays.\n" \ +" :type size: int or int sequence\n" #define BPY_PROPDEF_INT_STEP_DOC \ " :arg step: Step of increment/decrement in UI, in [1, 100], defaults to 1 (WARNING: unused " \ @@ -2415,11 +2651,15 @@ static int bpy_struct_id_used(StructRNA *srna, char *identifier) /* -------------------------------------------------------------------- */ /** \name Module Methods + * + * Functions that register RNA. + * + * \note The `self` argument is NULL when called from Python, + * but being abused from C so we can pass the `srna` along. + * This isn't incorrect since its a Python object - but be careful. + * * \{ */ -/* Function that sets RNA, NOTE - self is NULL when called from python, - * but being abused from C so we can pass the srna along. - * This isn't incorrect since its a python object - but be careful */ PyDoc_STRVAR(BPy_BoolProperty_doc, ".. function:: BoolProperty(name=\"\", " "description=\"\", " @@ -2440,95 +2680,108 @@ PyDoc_STRVAR(BPy_BoolProperty_doc, static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(BoolProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - bool def = false; - PropertyRNA *prop; - PyObject *pyopts = NULL; - PyObject *pyopts_override = NULL; - int opts = 0; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "name", - "description", - "default", - "options", - "override", - "tags", - "subtype", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssO&O!O!O!sOOO:BoolProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - PyC_ParseBool, - &def, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_BoolProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } + + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + bool default_value = false; + PropertyRNA *prop; + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_number_items, + .value = PROP_NONE, + }; - BPY_PROPDEF_SUBTYPE_CHECK(BoolProperty, - property_flag_items, - property_flag_override_items, - property_subtype_number_items); + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + static const char *_keywords[] = { + "attr", + "name", + "description", + "default", + "options", + "override", + "tags", + "subtype", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&|$ssO&O&O&O&O&OOO:BoolProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + PyC_ParseBool, + &default_value, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } + + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - prop = RNA_def_property(srna, id, PROP_BOOLEAN, subtype); - RNA_def_property_boolean_default(prop, def); - RNA_def_property_ui_text(prop, name ? name : id, description); + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_BOOLEAN, subtype_enum.value); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_boolean(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); + RNA_def_property_boolean_default(prop, default_value); + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_boolean(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); Py_RETURN_NONE; } @@ -2556,120 +2809,136 @@ PyDoc_STRVAR( static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(BoolVectorProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - bool def[PYRNA_STACK_ARRAY] = {0}; - int size = 3; - PropertyRNA *prop; - PyObject *pydef = NULL; - PyObject *pyopts = NULL; - PyObject *pyopts_override = NULL; - int opts = 0; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "name", - "description", - "default", - "options", - "override", - "tags", - "subtype", - "size", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssOO!O!O!siOOO:BoolVectorProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &pydef, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &size, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna( + self, args, kw, pymeth_BoolVectorProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_SUBTYPE_CHECK(BoolVectorProperty, - property_flag_items, - property_flag_override_items, - property_subtype_array_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + bool default_value[RNA_MAX_ARRAY_DIMENSION][PYRNA_STACK_ARRAY] = {{false}}; + struct BPyPropArrayLength array_len_info = {.len_total = 3}; + PropertyRNA *prop; + PyObject *default_py = NULL; + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_array_items, + .value = PROP_NONE, + }; + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (size < 1 || size > PYRNA_STACK_ARRAY) { - PyErr_Format( - PyExc_TypeError, - "BoolVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), - size); - return NULL; - } + static const char *_keywords[] = { + "attr", + "name", + "description", + "default", + "options", + "override", + "tags", + "subtype", + "size", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&|$ssOO&O&O&O&O&OOO:BoolVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_py, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + bpy_prop_array_length_parse, + &array_len_info, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - if (pydef && - PyC_AsArray( - def, pydef, size, &PyBool_Type, false, "BoolVectorProperty(default=sequence)") == -1) { + if (default_py != NULL) { + if (bpy_prop_array_from_py_with_dims(default_value[0], + sizeof(*default_value[0]), + default_py, + &array_len_info, + &PyBool_Type, + "BoolVectorProperty(default=sequence)") == -1) { return NULL; } + } - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } -#if 0 - prop = RNA_def_boolean_array( - srna, id, size, pydef ? def : NULL, name ? name : id, description); -#endif - prop = RNA_def_property(srna, id, PROP_BOOLEAN, subtype); - RNA_def_property_array(prop, size); - if (pydef) { - RNA_def_property_boolean_array_default(prop, def); - } - RNA_def_property_ui_text(prop, name ? name : id, description); + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_BOOLEAN, subtype_enum.value); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); + if (array_len_info.dims_len == 0) { + RNA_def_property_array(prop, array_len_info.len_total); + if (default_py != NULL) { + RNA_def_property_boolean_array_default(prop, default_value[0]); } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); + } + else { + RNA_def_property_multi_array(prop, array_len_info.dims_len, array_len_info.dims); + if (default_py != NULL) { + RNA_def_property_boolean_array_default(prop, &default_value[0][0]); } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_boolean_array(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); } + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_boolean_array(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -2699,106 +2968,122 @@ PyDoc_STRVAR( static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(IntProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0; - PropertyRNA *prop; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "name", - "description", - "default", - "min", - "max", - "soft_min", - "soft_max", - "step", - "options", - "override", - "tags", - "subtype", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssiiiiiiO!O!O!sOOO:IntProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &def, - &min, - &max, - &soft_min, - &soft_max, - &step, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_IntProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_SUBTYPE_CHECK(IntProperty, - property_flag_items, - property_flag_override_items, - property_subtype_number_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX; + int step = 1; + int default_value = 0; + PropertyRNA *prop; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_number_items, + .value = PROP_NONE, + }; + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + static const char *_keywords[] = { + "attr", + "name", + "description", + "default", + "min", + "max", + "soft_min", + "soft_max", + "step", + "options", + "override", + "tags", + "subtype", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&|$ssiiiiiiO&O&O&O&OOO:IntProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_value, + &min, + &max, + &soft_min, + &soft_max, + &step, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } + + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - prop = RNA_def_property(srna, id, PROP_INT, subtype); - RNA_def_property_int_default(prop, def); - RNA_def_property_ui_text(prop, name ? name : id, description); - RNA_def_property_range(prop, min, max); - RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3); + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_INT, subtype_enum.value); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_int(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); + RNA_def_property_int_default(prop, default_value); + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + RNA_def_property_range(prop, min, max); + RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_int(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -2832,128 +3117,151 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc, static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(IntVectorProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1; - int def[PYRNA_STACK_ARRAY] = {0}; - int size = 3; - PropertyRNA *prop; - PyObject *pydef = NULL; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "name", - "description", - "default", - "min", - "max", - "soft_min", - "soft_max", - "step", - "options", - "override", - "tags", - "subtype", - "size", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssOiiiiiO!O!O!siOOO:IntVectorProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &pydef, - &min, - &max, - &soft_min, - &soft_max, - &step, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &size, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna( + self, args, kw, pymeth_IntVectorProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } + + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX; + int step = 1; + int default_value[RNA_MAX_ARRAY_DIMENSION][PYRNA_STACK_ARRAY] = {0}; + struct BPyPropArrayLength array_len_info = {.len_total = 3}; + PropertyRNA *prop; + PyObject *default_py = NULL; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_array_items, + .value = PROP_NONE, + }; + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - BPY_PROPDEF_SUBTYPE_CHECK(IntVectorProperty, - property_flag_items, - property_flag_override_items, - property_subtype_array_items); + static const char *_keywords[] = { + "attr", + "name", + "description", + "default", + "min", + "max", + "soft_min", + "soft_max", + "step", + "options", + "override", + "tags", + "subtype", + "size", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&|$ssOiiiiiO&O&O&O&O&OOO:IntVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_py, + &min, + &max, + &soft_min, + &soft_max, + &step, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + bpy_prop_array_length_parse, + &array_len_info, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - if (size < 1 || size > PYRNA_STACK_ARRAY) { - PyErr_Format( - PyExc_TypeError, - "IntVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), - size); + if (default_py != NULL) { + if (bpy_prop_array_from_py_with_dims(default_value[0], + sizeof(*default_value[0]), + default_py, + &array_len_info, + &PyLong_Type, + "IntVectorProperty(default=sequence)") == -1) { return NULL; } + } - if (pydef && - PyC_AsArray( - def, pydef, size, &PyLong_Type, false, "IntVectorProperty(default=sequence)") == -1) { - return NULL; - } + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_INT, subtype_enum.value); + + if (array_len_info.dims_len == 0) { + RNA_def_property_array(prop, array_len_info.len_total); + if (default_py != NULL) { + RNA_def_property_int_array_default(prop, default_value[0]); } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; + } + else { + RNA_def_property_multi_array(prop, array_len_info.dims_len, array_len_info.dims); + if (default_py != NULL) { + RNA_def_property_int_array_default(prop, &default_value[0][0]); } + } - prop = RNA_def_property(srna, id, PROP_INT, subtype); - RNA_def_property_array(prop, size); - if (pydef) { - RNA_def_property_int_array_default(prop, def); - } - RNA_def_property_range(prop, min, max); - RNA_def_property_ui_text(prop, name ? name : id, description); - RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3); + RNA_def_property_range(prop, min, max); + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_int_array(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_int_array(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -2986,103 +3294,117 @@ PyDoc_STRVAR(BPy_FloatProperty_doc, static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(FloatProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, - def = 0.0f; - int precision = 2; - PropertyRNA *prop; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - const char *pyunit = NULL; - int unit = PROP_UNIT_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", "name", "description", "default", "min", "max", "soft_min", - "soft_max", "step", "precision", "options", "override", "tags", "subtype", - "unit", "update", "get", "set", NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssffffffiO!O!O!ssOOO:FloatProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &def, - &min, - &max, - &soft_min, - &soft_max, - &step, - &precision, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &pyunit, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_FloatProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, - property_flag_items, - property_flag_override_items, - property_subtype_number_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX; + float step = 3; + float default_value = 0.0f; + int precision = 2; + PropertyRNA *prop; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_number_items, + .value = PROP_NONE, + }; + struct BPy_EnumProperty_Parse unit_enum = { + .items = rna_enum_property_unit_items, + .value = PROP_UNIT_NONE, + }; - if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) { - PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit", pyunit); - return NULL; - } + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + static const char *_keywords[] = { + "attr", "name", "description", "default", "min", "max", "soft_min", + "soft_max", "step", "precision", "options", "override", "tags", "subtype", + "unit", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"O&|$ssffffffiO&O&O&O&O&OOO:FloatProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_value, + &min, + &max, + &soft_min, + &soft_max, + &step, + &precision, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + pyrna_enum_value_parse_string, + &unit_enum, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - prop = RNA_def_property(srna, id, PROP_FLOAT, subtype | unit); - RNA_def_property_float_default(prop, def); - RNA_def_property_range(prop, min, max); - RNA_def_property_ui_text(prop, name ? name : id, description); - RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision); + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_float(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_FLOAT, subtype_enum.value | unit_enum.value); + + RNA_def_property_float_default(prop, default_value); + RNA_def_property_range(prop, min, max); + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_float(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -3118,123 +3440,149 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc, static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(FloatVectorProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3; - float def[PYRNA_STACK_ARRAY] = {0.0f}; - int precision = 2, size = 3; - PropertyRNA *prop; - PyObject *pydef = NULL; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - const char *pyunit = NULL; - int unit = PROP_UNIT_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", "name", "description", "default", "min", "max", "soft_min", - "soft_max", "step", "precision", "options", "override", "tags", "subtype", - "unit", "size", "update", "get", "set", NULL, - }; - static _PyArg_Parser _parser = {"s#|$ssOfffffiO!O!O!ssiOOO:FloatVectorProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &pydef, - &min, - &max, - &soft_min, - &soft_max, - &step, - &precision, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &pyunit, - &size, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna( + self, args, kw, pymeth_FloatVectorProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty, - property_flag_items, - property_flag_override_items, - property_subtype_array_items); - - if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) { - PyErr_Format(PyExc_TypeError, "FloatVectorProperty(unit='%s'): invalid unit", pyunit); - return NULL; - } + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX; + float step = 3; + float default_value[RNA_MAX_ARRAY_DIMENSION][PYRNA_STACK_ARRAY] = {{0.0f}}; + int precision = 2; + struct BPyPropArrayLength array_len_info = {.len_total = 3}; + PropertyRNA *prop; + PyObject *default_py = NULL; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_array_items, + .value = PROP_NONE, + }; + struct BPy_EnumProperty_Parse unit_enum = { + .items = rna_enum_property_unit_items, + .value = PROP_UNIT_NONE, + }; - if (size < 1 || size > PYRNA_STACK_ARRAY) { - PyErr_Format( - PyExc_TypeError, - "FloatVectorProperty(size=%d): size must be between 0 and " STRINGIFY(PYRNA_STACK_ARRAY), - size); - return NULL; - } + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (pydef && - PyC_AsArray( - def, pydef, size, &PyFloat_Type, false, "FloatVectorProperty(default=sequence)") == - -1) { - return NULL; - } + static const char *_keywords[] = { + "attr", "name", "description", "default", "min", "max", "soft_min", + "soft_max", "step", "precision", "options", "override", "tags", "subtype", + "unit", "size", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = { + "O&|$ssOfffffiO&O&O&O&O&O&OOO:FloatVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_py, + &min, + &max, + &soft_min, + &soft_max, + &step, + &precision, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + pyrna_enum_value_parse_string, + &unit_enum, + bpy_prop_array_length_parse, + &array_len_info, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + if (default_py != NULL) { + if (bpy_prop_array_from_py_with_dims(default_value[0], + sizeof(*default_value[0]), + default_py, + &array_len_info, + &PyFloat_Type, + "FloatVectorProperty(default=sequence)") == -1) { return NULL; } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; + if (bpy_prop_array_is_matrix_compatible_ex(subtype_enum.value, &array_len_info)) { + bpy_prop_array_matrix_swap_row_column_vn(&default_value[0][0], &array_len_info); } + } - prop = RNA_def_property(srna, id, PROP_FLOAT, subtype | unit); - RNA_def_property_array(prop, size); - if (pydef) { - RNA_def_property_float_array_default(prop, def); - } - RNA_def_property_range(prop, min, max); - RNA_def_property_ui_text(prop, name ? name : id, description); - RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision); + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_FLOAT, subtype_enum.value | unit_enum.value); + + if (array_len_info.dims_len == 0) { + RNA_def_property_array(prop, array_len_info.len_total); + if (default_py != NULL) { + RNA_def_property_float_array_default(prop, default_value[0]); } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); + } + else { + RNA_def_property_multi_array(prop, array_len_info.dims_len, array_len_info.dims); + if (default_py != NULL) { + RNA_def_property_float_array_default(prop, &default_value[0][0]); } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_float_array(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); } + + RNA_def_property_range(prop, min, max); + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_float_array(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -3262,102 +3610,116 @@ PyDoc_STRVAR(BPy_StringProperty_doc, static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(StringProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = "", *def = ""; - Py_ssize_t id_len; - int maxlen = 0; - PropertyRNA *prop; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - const char *pysubtype = NULL; - int subtype = PROP_NONE; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "name", - "description", - "default", - "maxlen", - "options", - "override", - "tags", - "subtype", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#|$sssiO!O!O!sOOO:StringProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &name, - &description, - &def, - &maxlen, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &pysubtype, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_StringProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_SUBTYPE_CHECK(StringProperty, - property_flag_items, - property_flag_override_items, - property_subtype_string_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = "", *default_value = ""; + int maxlen = 0; + PropertyRNA *prop; - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + struct BPy_EnumProperty_Parse subtype_enum = { + .items = property_subtype_string_items, + .value = PROP_NONE, + }; + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - prop = RNA_def_property(srna, id, PROP_STRING, subtype); - if (maxlen != 0) { - /* +1 since it includes null terminator. */ - RNA_def_property_string_maxlength(prop, maxlen + 1); - } - if (def && def[0]) { - RNA_def_property_string_default(prop, def); - } - RNA_def_property_ui_text(prop, name ? name : id, description); + static const char *_keywords[] = { + "attr", + "name", + "description", + "default", + "maxlen", + "options", + "override", + "tags", + "subtype", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&|$sssiO&O&O&O&OOO:StringProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &name, + &description, + &default_value, + &maxlen, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + pyrna_enum_value_parse_string, + &subtype_enum, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_string(prop, get_fn, set_fn); - RNA_def_property_duplicate_pointers(srna, prop); + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } + + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_property(srna, id_data.value, PROP_STRING, subtype_enum.value); + + if (maxlen != 0) { + /* +1 since it includes null terminator. */ + RNA_def_property_string_maxlength(prop, maxlen + 1); + } + if (default_value && default_value[0]) { + RNA_def_property_string_default(prop, default_value); + } + RNA_def_property_ui_text(prop, name ? name : id_data.value, description); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_string(prop, get_fn, set_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -3419,151 +3781,167 @@ PyDoc_STRVAR( static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(EnumProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - PyObject *def = NULL; - Py_ssize_t id_len; - int defvalue = 0; - PyObject *items, *items_fast; - const EnumPropertyItem *eitems; - PropertyRNA *prop; - PyObject *pyopts = NULL; - int opts = 0; - PyObject *pyopts_override = NULL; - int opts_override = 0; - int prop_tags = 0; - bool is_itemf = false; - PyObject *update_fn = NULL; - PyObject *get_fn = NULL; - PyObject *set_fn = NULL; - PyObject *py_tags = NULL; - - static const char *_keywords[] = { - "attr", - "items", - "name", - "description", - "default", - "options", - "override", - "tags", - "update", - "get", - "set", - NULL, - }; - static _PyArg_Parser _parser = {"s#O|$ssOO!O!O!OOO:EnumProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &items, - &name, - &description, - &def, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &update_fn, - &get_fn, - &set_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_EnumProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_CHECK(EnumProperty, property_flag_enum_items, property_flag_override_items); - - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { - return NULL; - } - if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { - return NULL; - } + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + PyObject *default_py = NULL; + int default_value = 0; + PyObject *items, *items_fast; + const EnumPropertyItem *eitems; + PropertyRNA *prop; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_enum_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + bool is_itemf = false; + PyObject *update_fn = NULL; + PyObject *get_fn = NULL; + PyObject *set_fn = NULL; - if (def == Py_None) { - /* This allows to get same behavior when explicitly passing None as default value, - * and not defining a default value at all! */ - def = NULL; - } + static const char *_keywords[] = { + "attr", + "items", + "name", + "description", + "default", + "options", + "override", + "tags", + "update", + "get", + "set", + NULL, + }; + static _PyArg_Parser _parser = {"O&O|$ssOO&O&O&OOO:EnumProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &items, + &name, + &description, + &default_py, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + &update_fn, + &get_fn, + &set_fn)) { + return NULL; + } - /* items can be a list or a callable */ - if (PyFunction_Check( - items)) { /* don't 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 (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(get_fn, "get", 1) == -1) { + return NULL; + } + if (bpy_prop_callback_check(set_fn, "set", 2) == -1) { + return NULL; + } - if (def) { - /* Only support getting integer default values here. */ - if (!py_long_as_int(def, &defvalue)) { - /* NOTE: using type error here is odd but python does this for invalid arguments. */ - PyErr_SetString( - PyExc_TypeError, - "EnumProperty(...): 'default' can only be an integer when 'items' is a function"); - return NULL; - } - } + if (default_py == Py_None) { + /* This allows to get same behavior when explicitly passing None as default value, + * and not defining a default value at all! */ + default_py = NULL; + } - is_itemf = true; - eitems = DummyRNA_NULL_items; + /* items can be a list or a callable */ + if (PyFunction_Check( + items)) { /* don't 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; } - 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); - if (!eitems) { - Py_DECREF(items_fast); + if (default_py) { + /* Only support getting integer default values here. */ + if (!py_long_as_int(default_py, &default_value)) { + /* NOTE: using type error here is odd but python does this for invalid arguments. */ + PyErr_SetString( + PyExc_TypeError, + "EnumProperty(...): 'default' can only be an integer when 'items' is a function"); return NULL; } } - if (opts & PROP_ENUM_FLAG) { - prop = RNA_def_enum_flag(srna, id, eitems, defvalue, name ? name : id, description); - } - else { - prop = RNA_def_enum(srna, id, eitems, defvalue, name ? name : id, description); + 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; } - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_enum(prop, get_fn, set_fn, (is_itemf ? items : NULL)); - RNA_def_property_duplicate_pointers(srna, prop); + eitems = enum_items_from_py( + items_fast, (options_enum.value & PROP_ENUM_FLAG) != 0, default_py, &default_value); - if (is_itemf == false) { - /* NOTE: this must be postponed until after #RNA_def_property_duplicate_pointers - * otherwise if this is a generator it may free the strings before we copy them */ + if (!eitems) { Py_DECREF(items_fast); - - MEM_freeN((void *)eitems); + return NULL; } } + + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + if (options_enum.value & PROP_ENUM_FLAG) { + prop = RNA_def_enum_flag( + srna, id_data.value, eitems, default_value, name ? name : id_data.value, description); + } + else { + prop = RNA_def_enum( + srna, id_data.value, eitems, default_value, name ? name : id_data.value, description); + } + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_enum(prop, get_fn, set_fn, (is_itemf ? items : NULL)); + RNA_def_property_duplicate_pointers(srna, prop); + + if (is_itemf == false) { + /* NOTE: this must be postponed until after #RNA_def_property_duplicate_pointers + * otherwise if this is a generator it may free the strings before we copy them */ + Py_DECREF(items_fast); + + MEM_freeN((void *)eitems); + } + Py_RETURN_NONE; } @@ -3609,94 +3987,111 @@ PyDoc_STRVAR(BPy_PointerProperty_doc, PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(PointerProperty); - - if (srna) { - const char *id = NULL, *name = NULL, *description = ""; - Py_ssize_t id_len; - PropertyRNA *prop; - StructRNA *ptype; - PyObject *type = Py_None; - PyObject *pyopts = NULL; - PyObject *pyopts_override = NULL; - PyObject *py_tags = NULL; - int opts = 0; - int opts_override = 0; - int prop_tags = 0; - PyObject *update_fn = NULL, *poll_fn = NULL; - - static const char *_keywords[] = { - "attr", - "type", - "name", - "description", - "options", - "override", - "tags", - "poll", - "update", - NULL, - }; - static _PyArg_Parser _parser = {"s#O|$ssO!O!O!OO:PointerProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &type, - &name, - &description, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags, - &poll_fn, - &update_fn)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna( + self, args, kw, pymeth_PointerProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_CHECK(PointerProperty, property_flag_items, property_flag_override_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + PropertyRNA *prop; + StructRNA *ptype; + PyObject *type = Py_None; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; + PyObject *update_fn = NULL, *poll_fn = NULL; - ptype = pointer_type_from_py(type, "PointerProperty(...)"); - if (!ptype) { - return NULL; - } - if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) { - PyErr_Format(PyExc_TypeError, - "PointerProperty(...) expected an RNA type derived from %.200s or %.200s", - RNA_struct_ui_name(&RNA_ID), - RNA_struct_ui_name(&RNA_PropertyGroup)); - return NULL; - } - if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { - return NULL; - } - if (bpy_prop_callback_check(poll_fn, "poll", 2) == -1) { - return NULL; - } - prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } + static const char *_keywords[] = { + "attr", + "type", + "name", + "description", + "options", + "override", + "tags", + "poll", + "update", + NULL, + }; + static _PyArg_Parser _parser = {"O&O|$ssO&O&O&OO:PointerProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &type, + &name, + &description, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum, + &poll_fn, + &update_fn)) { + return NULL; + } - if (RNA_struct_idprops_contains_datablock(ptype)) { - if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { - RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); - } + ptype = pointer_type_from_py(type, "PointerProperty(...)"); + if (!ptype) { + return NULL; + } + if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup) && !RNA_struct_is_ID(ptype)) { + PyErr_Format(PyExc_TypeError, + "PointerProperty(...) expected an RNA type derived from %.200s or %.200s", + RNA_struct_ui_name(&RNA_ID), + RNA_struct_ui_name(&RNA_PropertyGroup)); + return NULL; + } + if (bpy_prop_callback_check(update_fn, "update", 2) == -1) { + return NULL; + } + if (bpy_prop_callback_check(poll_fn, "poll", 2) == -1) { + return NULL; + } + + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_pointer_runtime( + srna, id_data.value, ptype, name ? name : id_data.value, description); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + + if (RNA_struct_idprops_contains_datablock(ptype)) { + if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { + RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); } - bpy_prop_callback_assign_update(prop, update_fn); - bpy_prop_callback_assign_pointer(prop, poll_fn); - RNA_def_property_duplicate_pointers(srna, prop); } + bpy_prop_callback_assign_update(prop, update_fn); + bpy_prop_callback_assign_pointer(prop, poll_fn); + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } @@ -3715,83 +4110,98 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc, PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; - - BPY_PROPDEF_HEAD(CollectionProperty); - - if (srna) { - Py_ssize_t id_len; - const char *id = NULL, *name = NULL, *description = ""; - PropertyRNA *prop; - StructRNA *ptype; - PyObject *type = Py_None; - PyObject *pyopts = NULL; - PyObject *pyopts_override = NULL; - PyObject *py_tags = NULL; - int opts = 0; - int opts_override = 0; - int prop_tags = 0; - - static const char *_keywords[] = { - "attr", - "type", - "name", - "description", - "options", - "override", - "tags", - NULL, - }; - static _PyArg_Parser _parser = {"s#O|$ssO!O!O!:CollectionProperty", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, - kw, - &_parser, - &id, - &id_len, - &type, - &name, - &description, - &PySet_Type, - &pyopts, - &PySet_Type, - &pyopts_override, - &PySet_Type, - &py_tags)) { - return NULL; + { /* Keep this block first. */ + PyObject *deferred_result; + srna = bpy_prop_deferred_data_or_srna( + self, args, kw, pymeth_CollectionProperty, &deferred_result); + if (srna == NULL) { + return deferred_result; } + } - BPY_PROPDEF_CHECK( - CollectionProperty, property_flag_items, property_flag_override_collection_items); + struct BPy_PropIDParse id_data = { + .srna = srna, + }; + const char *name = NULL, *description = ""; + PropertyRNA *prop; + StructRNA *ptype; + PyObject *type = Py_None; + + struct BPy_EnumProperty_Parse options_enum = { + .items = property_flag_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse override_enum = { + .items = property_flag_override_collection_items, + .value = 0, + }; + struct BPy_EnumProperty_Parse_WithSRNA tags_enum = { + .srna = srna, + }; - ptype = pointer_type_from_py(type, "CollectionProperty(...):"); - if (!ptype) { - return NULL; - } + static const char *_keywords[] = { + "attr", + "type", + "name", + "description", + "options", + "override", + "tags", + NULL, + }; + static _PyArg_Parser _parser = {"O&O|$ssO&O&O&:CollectionProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, + kw, + &_parser, + bpy_prop_arg_parse_id, + &id_data, + &type, + &name, + &description, + pyrna_enum_bitfield_parse_set, + &options_enum, + pyrna_enum_bitfield_parse_set, + &override_enum, + bpy_prop_arg_parse_tag_defines, + &tags_enum)) { + return NULL; + } - if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) { - PyErr_Format(PyExc_TypeError, - "CollectionProperty(...) expected an RNA type derived from %.200s", - RNA_struct_ui_name(&RNA_PropertyGroup)); - return NULL; - } + ptype = pointer_type_from_py(type, "CollectionProperty(...):"); + if (!ptype) { + return NULL; + } - prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description); - if (py_tags) { - RNA_def_property_tags(prop, prop_tags); - } - if (pyopts) { - bpy_prop_assign_flag(prop, opts); - } - if (pyopts_override) { - bpy_prop_assign_flag_override(prop, opts_override); - } + if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) { + PyErr_Format(PyExc_TypeError, + "CollectionProperty(...) expected an RNA type derived from %.200s", + RNA_struct_ui_name(&RNA_PropertyGroup)); + return NULL; + } - if (RNA_struct_idprops_contains_datablock(ptype)) { - if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { - RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); - } + if (id_data.prop_free_handle != NULL) { + RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle); + } + prop = RNA_def_collection_runtime( + srna, id_data.value, ptype, name ? name : id_data.value, description); + + if (tags_enum.base.is_set) { + RNA_def_property_tags(prop, tags_enum.base.value); + } + if (options_enum.is_set) { + bpy_prop_assign_flag(prop, options_enum.value); + } + if (override_enum.is_set) { + bpy_prop_assign_flag_override(prop, override_enum.value); + } + + if (RNA_struct_idprops_contains_datablock(ptype)) { + if (RNA_struct_is_a(srna, &RNA_PropertyGroup)) { + RNA_def_struct_flag(srna, STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES); } - RNA_def_property_duplicate_pointers(srna, prop); } + RNA_def_property_duplicate_pointers(srna, prop); + Py_RETURN_NONE; } |