Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/intern/bpy_rna.c')
-rw-r--r--source/blender/python/intern/bpy_rna.c373
1 files changed, 303 insertions, 70 deletions
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 5414c4e4204..33ac58dadb1 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -37,6 +37,7 @@
#include "RNA_types.h"
+#include "BLI_bitmap.h"
#include "BLI_dynstr.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
@@ -920,7 +921,7 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self)
type = RNA_property_type(self->prop);
- if (RNA_enum_id_from_value(property_type_items, type, &type_id) == 0) {
+ if (RNA_enum_id_from_value(rna_enum_property_type_items, type, &type_id) == 0) {
PyErr_SetString(PyExc_RuntimeError, "could not use property type, internal error"); /* should never happen */
return NULL;
}
@@ -1176,6 +1177,69 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
return 0;
}
+/**
+ * Takes a set of strings and map it to and array of booleans.
+ *
+ * Useful when the values aren't flags.
+ *
+ * \param type_convert_sign: Maps signed to unsigned range,
+ * needed when we want to use the full range of a signed short/char.
+ */
+BLI_bitmap *pyrna_set_to_enum_bitmap(
+ EnumPropertyItem *items, PyObject *value,
+ int type_size, bool type_convert_sign,
+ int bitmap_size,
+ const char *error_prefix)
+{
+ /* set looping */
+ Py_ssize_t pos = 0;
+ Py_ssize_t hash = 0;
+ PyObject *key;
+
+ BLI_bitmap *bitmap = BLI_BITMAP_NEW(bitmap_size, __func__);
+
+ while (_PySet_NextEntry(value, &pos, &key, &hash)) {
+ const char *param = _PyUnicode_AsString(key);
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s expected a string, not %.200s",
+ error_prefix, Py_TYPE(key)->tp_name);
+ goto error;
+ }
+
+ int ret;
+ if (pyrna_enum_value_from_id(items, param, &ret, error_prefix) == -1) {
+ goto error;
+ }
+
+ int index = ret;
+
+ if (type_convert_sign) {
+ if (type_size == 2) {
+ union { signed short as_signed; unsigned short as_unsigned; } ret_convert;
+ ret_convert.as_signed = (signed short)ret;
+ index = (int)ret_convert.as_unsigned;
+ }
+ else if (type_size == 1) {
+ union { signed char as_signed; unsigned char as_unsigned; } ret_convert;
+ ret_convert.as_signed = (signed char)ret;
+ index = (int)ret_convert.as_unsigned;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ BLI_assert(index < bitmap_size);
+ BLI_BITMAP_ENABLE(bitmap, index);
+ }
+
+ return bitmap;
+
+error:
+ MEM_freeN(bitmap);
+ return NULL;
+}
+
/* 'value' _must_ be a set type, error check before calling */
int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix)
{
@@ -1303,27 +1367,32 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ret = PyUnicode_FromString(enum_item->identifier);
}
else {
- const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
-
- /* prefer not fail silently in case of api errors, maybe disable it later */
- printf("RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'\n",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
-
-#if 0 /* gives python decoding errors while generating docs :( */
- char error_str[256];
- BLI_snprintf(error_str, sizeof(error_str),
- "RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
-
- PyErr_Warn(PyExc_RuntimeWarning, error_str);
+ RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free);
+
+ /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */
+ if (enum_item != DummyRNA_NULL_items) {
+ const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
+
+ /* prefer not fail silently in case of api errors, maybe disable it later */
+ printf("RNA Warning: Current value \"%d\" "
+ "matches no enum in '%s', '%s', '%s'\n",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
+
+#if 0 /* gives python decoding errors while generating docs :( */
+ char error_str[256];
+ BLI_snprintf(error_str, sizeof(error_str),
+ "RNA Warning: Current value \"%d\" "
+ "matches no enum in '%s', '%s', '%s'",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
+
+ PyErr_Warn(PyExc_RuntimeWarning, error_str);
#endif
- if (ptr_name)
- MEM_freeN((void *)ptr_name);
+ if (ptr_name)
+ MEM_freeN((void *)ptr_name);
+ }
ret = PyUnicode_FromString("");
}
@@ -2633,13 +2702,147 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
}
}
+/**
+ * Helpers for #prop_subscript_ass_array_slice
+ */
+
+static PyObject *prop_subscript_ass_array_slice__as_seq_fast(PyObject *value, int length)
+{
+ PyObject *value_fast;
+ if (!(value_fast = PySequence_Fast(
+ value,
+ "bpy_prop_array[slice] = value: "
+ "element in assignment is not a sequence type")))
+ {
+ return NULL;
+ }
+ else if (PySequence_Fast_GET_SIZE(value_fast) != length) {
+ Py_DECREF(value_fast);
+ PyErr_SetString(
+ PyExc_ValueError,
+ "bpy_prop_array[slice] = value: "
+ "re-sizing bpy_struct element in arrays isn't supported");
+
+ return NULL;
+ }
+ else {
+ return value_fast;
+ }
+}
+
+static int prop_subscript_ass_array_slice__float_recursive(
+ PyObject **value_items, float *value,
+ int totdim, const int dimsize[],
+ const float range[2])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__float_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1], range);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ const float min = range[0], max = range[1];
+ int i;
+ for (i = 0; i != length; i++) {
+ float v = PyFloat_AsDouble(value_items[i]);
+ CLAMP(v, min, max);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
+static int prop_subscript_ass_array_slice__int_recursive(
+ PyObject **value_items, int *value,
+ int totdim, const int dimsize[],
+ const int range[2])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__int_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1], range);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ const int min = range[0], max = range[1];
+ int i;
+ for (i = 0; i != length; i++) {
+ int v = PyLong_AsLong(value_items[i]);
+ CLAMP(v, min, max);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
+static int prop_subscript_ass_array_slice__bool_recursive(
+ PyObject **value_items, int *value,
+ int totdim, const int dimsize[])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__bool_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1]);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ int i;
+ for (i = 0; i != length; i++) {
+ int v = PyLong_AsLong(value_items[i]);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
/* could call (pyrna_py_to_prop_array_index(self, i, value) in a loop but it is slow */
-static int prop_subscript_ass_array_slice(PointerRNA *ptr, PropertyRNA *prop,
- int start, int stop, int length, PyObject *value_orig)
+static int prop_subscript_ass_array_slice(
+ PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset,
+ int start, int stop, int length, PyObject *value_orig)
{
+ const int length_flat = RNA_property_array_length(ptr, prop);
PyObject *value;
PyObject **value_items;
- int count;
void *values_alloc = NULL;
int ret = 0;
@@ -2660,70 +2863,85 @@ static int prop_subscript_ass_array_slice(PointerRNA *ptr, PropertyRNA *prop,
return -1;
}
+ int dimsize[3];
+ int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
+ if (totdim > 1) {
+ BLI_assert(dimsize[arraydim] == length);
+ }
+
+ int span = 1;
+ if (totdim > 1) {
+ for (int i = arraydim + 1; i < totdim; i++) {
+ span *= dimsize[i];
+ }
+ }
+
value_items = PySequence_Fast_ITEMS(value);
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
{
float values_stack[PYRNA_STACK_ARRAY];
- float *values, fval;
-
- float min, max;
- RNA_property_float_range(ptr, prop, &min, &max);
-
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(float) * length); }
- else { values = values_stack; }
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
+ float *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
RNA_property_float_get_array(ptr, prop, values);
-
- for (count = start; count < stop; count++) {
- fval = PyFloat_AsDouble(value_items[count - start]);
- CLAMP(fval, min, max);
- values[count] = fval;
}
+ float range[2];
+ RNA_property_float_range(ptr, prop, &range[0], &range[1]);
+
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__float_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim],
+ range);
+
if (PyErr_Occurred()) ret = -1;
else RNA_property_float_set_array(ptr, prop, values);
break;
}
- case PROP_BOOLEAN:
+ case PROP_INT:
{
int values_stack[PYRNA_STACK_ARRAY];
- int *values;
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(int) * length); }
- else { values = values_stack; }
+ int *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
+ RNA_property_int_get_array(ptr, prop, values);
+ }
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
- RNA_property_boolean_get_array(ptr, prop, values);
+ int range[2];
+ RNA_property_int_range(ptr, prop, &range[0], &range[1]);
- for (count = start; count < stop; count++)
- values[count] = PyLong_AsLong(value_items[count - start]);
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__int_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim],
+ range);
if (PyErr_Occurred()) ret = -1;
- else RNA_property_boolean_set_array(ptr, prop, values);
+ else RNA_property_int_set_array(ptr, prop, values);
break;
}
- case PROP_INT:
+ case PROP_BOOLEAN:
{
int values_stack[PYRNA_STACK_ARRAY];
- int *values, ival;
-
- int min, max;
- RNA_property_int_range(ptr, prop, &min, &max);
+ int *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(int) * length); }
- else { values = values_stack; }
-
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
- RNA_property_int_get_array(ptr, prop, values);
-
- for (count = start; count < stop; count++) {
- ival = PyLong_AsLong(value_items[count - start]);
- CLAMP(ival, min, max);
- values[count] = ival;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
+ RNA_property_boolean_get_array(ptr, prop, values);
}
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__bool_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim]);
+
if (PyErr_Occurred()) ret = -1;
- else RNA_property_int_set_array(ptr, prop, values);
+ else RNA_property_boolean_set_array(ptr, prop, values);
break;
}
default:
@@ -2784,7 +3002,7 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, PyObject *
}
}
else if (PySlice_Check(key)) {
- int len = RNA_property_array_length(&self->ptr, self->prop);
+ Py_ssize_t len = pyrna_prop_array_length(self);
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx(key, len, &start, &stop, &step, &slicelength) < 0) {
@@ -2794,7 +3012,9 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, PyObject *
ret = 0; /* do nothing */
}
else if (step == 1) {
- ret = prop_subscript_ass_array_slice(&self->ptr, self->prop, start, stop, len, value);
+ ret = prop_subscript_ass_array_slice(
+ &self->ptr, self->prop, self->arraydim, self->arrayoffset,
+ start, stop, len, value);
}
else {
PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
@@ -6678,6 +6898,21 @@ PyObject *BPY_rna_types(void)
/* add __name__ since help() expects its */
PyDict_SetItem(pyrna_basetype_Type.tp_dict, bpy_intern_str___name__, bpy_intern_str_bpy_types);
+ /* internal base types we have no other accessors for */
+ {
+ PyTypeObject *pyrna_types[] = {
+ &pyrna_struct_meta_idprop_Type,
+ &pyrna_struct_Type,
+ &pyrna_prop_Type,
+ &pyrna_prop_array_Type,
+ &pyrna_prop_collection_Type,
+ &pyrna_func_Type,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(pyrna_types); i += 1) {
+ PyDict_SetItemString(pyrna_basetype_Type.tp_dict, pyrna_types[i]->tp_name, (PyObject *)pyrna_types[i]);
+ }
+ }
self = (BPy_BaseTypeRNA *)PyObject_NEW(BPy_BaseTypeRNA, &pyrna_basetype_Type);
@@ -7128,12 +7363,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PointerRNA funcptr;
int err = 0, i, ret_len = 0, arg_count;
int flag = RNA_function_flag(func);
- const char is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
- const char is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
-
- /* annoying!, need to check if the screen gets set to NULL which is a
- * hint that the file was actually re-loaded. */
- char is_valid_wm;
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+ const bool is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
PropertyRNA *pret_single = NULL;
void *retdata_single = NULL;
@@ -7160,7 +7391,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (C == NULL)
C = BPy_GetContext();
- is_valid_wm = (CTX_wm_manager(C) != NULL);
+ /* annoying!, need to check if the screen gets set to NULL which is a
+ * hint that the file was actually re-loaded. */
+ const bool is_valid_wm = (CTX_wm_manager(C) != NULL);
bpy_context_set(C, &gilstate);