Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
233 lines
5.8 KiB
C++
233 lines
5.8 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup pygen
|
|
*
|
|
* Python/RNA utilities.
|
|
*
|
|
* RNA functions that aren't part of the `bpy_rna.cc` API.
|
|
*/
|
|
|
|
/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
|
|
#define PY_SSIZE_T_CLEAN
|
|
|
|
#include <Python.h>
|
|
|
|
#include "py_capi_rna.h"
|
|
|
|
#include "BLI_bitmap.h"
|
|
#include "BLI_dynstr.h"
|
|
|
|
#include "RNA_access.hh"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Enum Utilities
|
|
* \{ */
|
|
|
|
char *pyrna_enum_repr(const EnumPropertyItem *item)
|
|
{
|
|
DynStr *dynstr = BLI_dynstr_new();
|
|
|
|
/* We can't compare with the first element in the array
|
|
* since it may be a category (without an identifier). */
|
|
for (bool is_first = true; item->identifier; item++) {
|
|
if (item->identifier[0]) {
|
|
BLI_dynstr_appendf(dynstr, is_first ? "'%s'" : ", '%s'", item->identifier);
|
|
is_first = false;
|
|
}
|
|
}
|
|
|
|
char *cstring = BLI_dynstr_get_cstring(dynstr);
|
|
BLI_dynstr_free(dynstr);
|
|
return cstring;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Enum Conversion Utilities
|
|
* \{ */
|
|
|
|
int pyrna_enum_value_from_id(const EnumPropertyItem *item,
|
|
const char *identifier,
|
|
int *r_value,
|
|
const char *error_prefix)
|
|
{
|
|
if (RNA_enum_value_from_id(item, identifier, r_value) == 0) {
|
|
const char *enum_str = pyrna_enum_repr(item);
|
|
PyErr_Format(
|
|
PyExc_ValueError, "%s: '%.200s' not found in (%s)", error_prefix, identifier, enum_str);
|
|
MEM_freeN((void *)enum_str);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BLI_bitmap *pyrna_enum_bitmap_from_set(const 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_AsUTF8(key);
|
|
if (param == nullptr) {
|
|
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;
|
|
ushort 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;
|
|
uchar as_unsigned;
|
|
} ret_convert;
|
|
ret_convert.as_signed = (signed char)ret;
|
|
index = int(ret_convert.as_unsigned);
|
|
}
|
|
else {
|
|
BLI_assert_unreachable();
|
|
}
|
|
}
|
|
BLI_assert(index < bitmap_size);
|
|
BLI_BITMAP_ENABLE(bitmap, index);
|
|
}
|
|
|
|
return bitmap;
|
|
|
|
error:
|
|
MEM_freeN(bitmap);
|
|
return nullptr;
|
|
}
|
|
|
|
int pyrna_enum_bitfield_from_set(const EnumPropertyItem *items,
|
|
PyObject *value,
|
|
int *r_value,
|
|
const char *error_prefix)
|
|
{
|
|
/* Set of enum items, concatenate all values with OR. */
|
|
int ret, flag = 0;
|
|
|
|
/* Set looping. */
|
|
Py_ssize_t pos = 0;
|
|
Py_ssize_t hash = 0;
|
|
PyObject *key;
|
|
|
|
*r_value = 0;
|
|
|
|
while (_PySet_NextEntry(value, &pos, &key, &hash)) {
|
|
const char *param = PyUnicode_AsUTF8(key);
|
|
|
|
if (param == nullptr) {
|
|
PyErr_Format(PyExc_TypeError,
|
|
"%.200s expected a string, not %.200s",
|
|
error_prefix,
|
|
Py_TYPE(key)->tp_name);
|
|
return -1;
|
|
}
|
|
|
|
if (pyrna_enum_value_from_id(items, param, &ret, error_prefix) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
flag |= ret;
|
|
}
|
|
|
|
*r_value = flag;
|
|
return 0;
|
|
}
|
|
|
|
PyObject *pyrna_enum_bitfield_as_set(const EnumPropertyItem *items, int value)
|
|
{
|
|
PyObject *ret = PySet_New(nullptr);
|
|
const char *identifier[RNA_ENUM_BITFLAG_SIZE + 1];
|
|
|
|
if (RNA_enum_bitflag_identifiers(items, value, identifier)) {
|
|
PyObject *item;
|
|
int index;
|
|
for (index = 0; identifier[index]; index++) {
|
|
item = PyUnicode_FromString(identifier[index]);
|
|
PySet_Add(ret, item);
|
|
Py_DECREF(item);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Argument Parsing Helpers
|
|
* \{ */
|
|
|
|
int pyrna_enum_value_parse_string(PyObject *o, void *p)
|
|
{
|
|
const char *identifier = PyUnicode_AsUTF8(o);
|
|
if (identifier == nullptr) {
|
|
PyErr_Format(PyExc_TypeError, "expected a string enum, not %.200s", Py_TYPE(o)->tp_name);
|
|
return 0;
|
|
}
|
|
BPy_EnumProperty_Parse *parse_data = static_cast<BPy_EnumProperty_Parse *>(p);
|
|
if (pyrna_enum_value_from_id(
|
|
parse_data->items, identifier, &parse_data->value, "enum identifier") == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
parse_data->value_orig = o;
|
|
parse_data->is_set = true;
|
|
return 1;
|
|
}
|
|
|
|
int pyrna_enum_bitfield_parse_set(PyObject *o, void *p)
|
|
{
|
|
if (!PySet_Check(o)) {
|
|
PyErr_Format(PyExc_TypeError, "expected a set, not %.200s", Py_TYPE(o)->tp_name);
|
|
return 0;
|
|
}
|
|
|
|
BPy_EnumProperty_Parse *parse_data = static_cast<BPy_EnumProperty_Parse *>(p);
|
|
if (pyrna_enum_bitfield_from_set(
|
|
parse_data->items, o, &parse_data->value, "enum identifier set") == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
parse_data->value_orig = o;
|
|
parse_data->is_set = true;
|
|
return 1;
|
|
}
|
|
|
|
/** \} */
|