Files
test2/source/blender/makesrna/intern/rna_access.cc
Campbell Barton 3de916ca25 RNA: support for marking properties as deprecated
Deprecation meta-data support for RNA properties.

- Properties may have a deprecated note and version.
- Warnings shown when these are accessed from Python.
- A note is included in the generated documentation.

Support for marking functions as deprecated can be added in the future.

Ref !139487
2025-07-29 22:09:59 +10:00

7083 lines
194 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup RNA
*/
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <sstream>
#include <fmt/format.h>
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_mutex.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.hh"
#include "BKE_anim_data.hh"
#include "BKE_collection.hh"
#include "BKE_context.hh"
#include "BKE_fcurve.hh"
#include "BKE_global.hh"
#include "BKE_idprop.hh"
#include "BKE_idtype.hh"
#include "BKE_lib_id.hh"
#include "BKE_lib_override.hh"
#include "BKE_library.hh"
#include "BKE_main.hh"
#include "BKE_node.hh"
#include "BKE_report.hh"
#include "CLG_log.h"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "RNA_enum_types.hh"
#include "RNA_path.hh"
#include "RNA_types.hh"
#include "UI_resources.hh"
#include "WM_api.hh"
#include "WM_message.hh"
/* flush updates */
#include "WM_types.hh"
#ifdef WITH_PYTHON
# include "BPY_extern.hh"
#endif
#include "rna_access_internal.hh"
#include "rna_internal.hh"
static CLG_LogRef LOG = {"rna.access"};
/* Init/Exit */
/* NOTE: Initializing this object here is fine for now, as it should not allocate any memory. */
extern const PointerRNA PointerRNA_NULL = {};
void RNA_init()
{
StructRNA *srna;
BLENDER_RNA.structs_map = BLI_ghash_str_new_ex(__func__, 2048);
BLENDER_RNA.structs_len = 0;
for (srna = static_cast<StructRNA *>(BLENDER_RNA.structs.first); srna;
srna = static_cast<StructRNA *>(srna->cont.next))
{
if (!srna->cont.prop_lookup_set) {
srna->cont.prop_lookup_set =
MEM_new<blender::CustomIDVectorSet<PropertyRNA *, PropertyRNAIdentifierGetter>>(
__func__);
LISTBASE_FOREACH (PropertyRNA *, prop, &srna->cont.properties) {
if (!(prop->flag_internal & PROP_INTERN_BUILTIN)) {
srna->cont.prop_lookup_set->add(prop);
}
}
}
BLI_assert(srna->flag & STRUCT_PUBLIC_NAMESPACE);
BLI_ghash_insert(BLENDER_RNA.structs_map, (void *)srna->identifier, srna);
BLENDER_RNA.structs_len += 1;
}
}
void RNA_bpy_exit()
{
#ifdef WITH_PYTHON
StructRNA *srna;
for (srna = static_cast<StructRNA *>(BLENDER_RNA.structs.first); srna;
srna = static_cast<StructRNA *>(srna->cont.next))
{
/* NOTE(@ideasman42): each call locks the Python's GIL. Only locking/unlocking once
* is possible but gives barely measurable speedup (< ~1millisecond) so leave as-is. */
BPY_free_srna_pytype(srna);
}
#endif
}
void RNA_exit()
{
StructRNA *srna;
for (srna = static_cast<StructRNA *>(BLENDER_RNA.structs.first); srna;
srna = static_cast<StructRNA *>(srna->cont.next))
{
MEM_SAFE_DELETE(srna->cont.prop_lookup_set);
}
RNA_free(&BLENDER_RNA);
}
/* Pointer */
BLI_INLINE void rna_pointer_refine(PointerRNA &r_ptr)
{
while (r_ptr.type->refine) {
StructRNA *type = r_ptr.type->refine(&r_ptr);
if (type == r_ptr.type) {
break;
}
r_ptr.type = type;
}
}
void rna_pointer_create_with_ancestors(const PointerRNA &parent,
StructRNA *type,
void *data,
PointerRNA &r_ptr)
{
if (data) {
if (type && type->flag & STRUCT_ID) {
/* Currently, assume that an ID PointerRNA never has an ancestor.
* NOTE: This may become an issue for embedded IDs in the future, see also
* #PointerRNA::ancestors docs. */
r_ptr = {static_cast<ID *>(data), type, data};
}
else {
r_ptr = {parent.owner_id, type, data, parent};
}
rna_pointer_refine(r_ptr);
}
else {
r_ptr = {};
}
}
PointerRNA RNA_main_pointer_create(Main *main)
{
return {nullptr, &RNA_BlendData, main};
}
PointerRNA RNA_id_pointer_create(ID *id)
{
if (id) {
PointerRNA ptr{id, ID_code_to_RNA_type(GS(id->name)), id};
rna_pointer_refine(ptr);
return ptr;
}
return PointerRNA_NULL;
}
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
{
PointerRNA ptr{id, type, data};
if (data) {
rna_pointer_refine(ptr);
}
return ptr;
}
PointerRNA RNA_pointer_create_with_parent(const PointerRNA &parent, StructRNA *type, void *data)
{
PointerRNA result;
rna_pointer_create_with_ancestors(parent, type, data, result);
return result;
}
PointerRNA RNA_pointer_create_id_subdata(ID &id, StructRNA *type, void *data)
{
PointerRNA parent = RNA_id_pointer_create(&id);
PointerRNA result;
rna_pointer_create_with_ancestors(parent, type, data, result);
return result;
}
PointerRNA RNA_pointer_create_from_ancestor(const PointerRNA &ptr, const int ancestor_idx)
{
if (ancestor_idx >= ptr.ancestors.size()) {
BLI_assert_unreachable();
return {};
}
/* NOTE: No call to `rna_pointer_refine` should be needed here, as ancestors info should have
* been created from already refined PointerRNA data. */
PointerRNA ancestor_ptr{ptr.owner_id,
ptr.ancestors[ancestor_idx].type,
ptr.ancestors[ancestor_idx].data,
ptr.ancestors.as_span().slice(0, ancestor_idx)};
#ifndef NDEBUG
StructRNA *type = ancestor_ptr.type;
rna_pointer_refine(ancestor_ptr);
BLI_assert(type == ancestor_ptr.type);
#endif
return ancestor_ptr;
}
bool RNA_pointer_is_null(const PointerRNA *ptr)
{
return (ptr->data == nullptr) || (ptr->owner_id == nullptr) || (ptr->type == nullptr);
}
PointerRNA RNA_blender_rna_pointer_create()
{
PointerRNA ptr = {};
ptr.owner_id = nullptr;
ptr.type = &RNA_BlenderRNA;
ptr.data = &BLENDER_RNA;
return ptr;
}
PointerRNA RNA_pointer_recast(PointerRNA *ptr)
{
#if 0 /* works but this case if covered by more general code below. */
if (RNA_struct_is_ID(ptr->type)) {
/* simple case */
*r_ptr = RNA_id_pointer_create(ptr->owner_id);
}
else
#endif
{
PointerRNA r_ptr{*ptr};
PointerRNA t_ptr{*ptr};
StructRNA *base;
for (base = ptr->type->base; base; base = base->base) {
t_ptr.type = base;
rna_pointer_refine(t_ptr);
if (t_ptr.type && t_ptr.type != ptr->type) {
r_ptr = t_ptr;
}
}
return r_ptr;
}
}
/* ID Properties */
void rna_idproperty_touch(IDProperty *idprop)
{
/* so the property is seen as 'set' by rna */
idprop->flag &= ~IDP_FLAG_GHOST;
}
IDProperty **RNA_struct_idprops_p(PointerRNA *ptr)
{
StructRNA *type = ptr->type;
if (type == nullptr) {
return nullptr;
}
if (type->idproperties == nullptr) {
return nullptr;
}
return type->idproperties(ptr);
}
IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create)
{
IDProperty **property_ptr = RNA_struct_idprops_p(ptr);
if (property_ptr == nullptr) {
return nullptr;
}
if (create && *property_ptr == nullptr) {
*property_ptr =
blender::bke::idprop::create_group("user_properties", IDP_FLAG_STATIC_TYPE).release();
}
return *property_ptr;
}
bool RNA_struct_idprops_check(const StructRNA *srna)
{
return (srna && srna->idproperties);
}
IDProperty *rna_idproperty_find(PointerRNA *ptr, const char *name)
{
IDProperty *group = RNA_struct_idprops(ptr, false);
if (!group) {
return nullptr;
}
if (group->type == IDP_GROUP) {
return IDP_GetPropertyFromGroup(group, name);
}
/* Not sure why that happens sometimes, with nested properties... */
/* Seems to be actually array prop, name is usually "0"... To be sorted out later. */
#if 0
printf("Got unexpected IDProp container when trying to retrieve %s: %d\n", name, group->type);
#endif
return nullptr;
}
IDProperty **RNA_struct_system_idprops_p(PointerRNA *ptr)
{
StructRNA *type = ptr->type;
if (type == nullptr) {
return nullptr;
}
if (type->system_idproperties == nullptr) {
return nullptr;
}
return type->system_idproperties(ptr);
}
IDProperty *RNA_struct_system_idprops(PointerRNA *ptr, bool create)
{
IDProperty **property_ptr = RNA_struct_system_idprops_p(ptr);
if (property_ptr == nullptr) {
return nullptr;
}
if (create && *property_ptr == nullptr) {
*property_ptr =
blender::bke::idprop::create_group("system_properties", IDP_FLAG_STATIC_TYPE).release();
}
return *property_ptr;
}
bool RNA_struct_system_idprops_check(StructRNA *srna)
{
return (srna && srna->system_idproperties);
}
IDProperty *rna_system_idproperty_find(PointerRNA *ptr, const char *name)
{
IDProperty *group = RNA_struct_system_idprops(ptr, false);
if (!group) {
return nullptr;
}
if (group->type == IDP_GROUP) {
return IDP_GetPropertyFromGroup(group, name);
}
/* Not sure why that happens sometimes, with nested properties... */
/* Seems to be actually array prop, name is usually "0"... To be sorted out later. */
#if 0
printf("Got unexpected IDProp container when trying to retrieve %s: %d\n", name, group->type);
#endif
return nullptr;
}
static void rna_system_idproperty_free(PointerRNA *ptr, const char *name)
{
IDProperty *group = RNA_struct_system_idprops(ptr, false);
if (group) {
IDProperty *idprop = IDP_GetPropertyFromGroup(group, name);
if (idprop) {
IDP_FreeFromGroup(group, idprop);
}
}
}
static int rna_ensure_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
int arraylen[RNA_MAX_ARRAY_DIMENSION];
return (prop->getlength && ptr->data) ? prop->getlength(ptr, arraylen) :
int(prop->totarraylength);
}
IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_ARRAY) {
return idprop->len;
}
return 0;
}
static bool rna_ensure_property_array_check(PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
return (prop->getlength || prop->totarraylength);
}
IDProperty *idprop = (IDProperty *)prop;
return (idprop->type == IDP_ARRAY);
}
static void rna_ensure_property_multi_array_length(const PointerRNA *ptr,
PropertyRNA *prop,
int length[])
{
if (prop->magic == RNA_MAGIC) {
if (prop->getlength) {
prop->getlength(ptr, length);
}
else {
memcpy(length, prop->arraylength, prop->arraydimension * sizeof(int));
}
}
else {
IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_ARRAY) {
length[0] = idprop->len;
}
else {
length[0] = 0;
}
}
}
static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDProperty *idprop)
{
/* this verifies if the idproperty actually matches the property
* description and otherwise removes it. this is to ensure that
* rna property access is type safe, e.g. if you defined the rna
* to have a certain array length you can count on that staying so */
switch (idprop->type) {
case IDP_IDPARRAY:
if (prop->type != PROP_COLLECTION) {
return false;
}
break;
case IDP_ARRAY:
if (rna_ensure_property_array_length(ptr, prop) != idprop->len) {
return false;
}
if (idprop->subtype == IDP_FLOAT && prop->type != PROP_FLOAT) {
return false;
}
if (idprop->subtype == IDP_BOOLEAN && prop->type != PROP_BOOLEAN) {
return false;
}
if (idprop->subtype == IDP_INT && !ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) {
return false;
}
break;
case IDP_INT:
if (!ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) {
return false;
}
break;
case IDP_BOOLEAN:
if (prop->type != PROP_BOOLEAN) {
return false;
}
break;
case IDP_FLOAT:
case IDP_DOUBLE:
if (prop->type != PROP_FLOAT) {
return false;
}
break;
case IDP_STRING:
if (prop->type != PROP_STRING) {
return false;
}
break;
case IDP_GROUP:
case IDP_ID:
if (prop->type != PROP_POINTER) {
return false;
}
break;
default:
return false;
}
return true;
}
static PropertyRNA *typemap[IDP_NUMTYPES] = {
&rna_PropertyGroupItem_string,
&rna_PropertyGroupItem_int,
&rna_PropertyGroupItem_float,
nullptr,
nullptr,
nullptr,
&rna_PropertyGroupItem_group,
&rna_PropertyGroupItem_id,
&rna_PropertyGroupItem_double,
&rna_PropertyGroupItem_idp_array,
&rna_PropertyGroupItem_bool,
};
static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
nullptr,
&rna_PropertyGroupItem_int_array,
&rna_PropertyGroupItem_float_array,
nullptr,
nullptr,
nullptr,
&rna_PropertyGroupItem_collection,
nullptr,
&rna_PropertyGroupItem_double_array,
nullptr,
&rna_PropertyGroupItem_bool_array,
};
void rna_property_rna_or_id_get(PropertyRNA *prop,
PointerRNA *ptr,
PropertyRNAOrID *r_prop_rna_or_id)
{
/* This is quite a hack, but avoids some complexity in the API. we
* pass IDProperty structs as PropertyRNA pointers to the outside.
* We store some bytes in PropertyRNA structs that allows us to
* distinguish it from IDProperty structs. If it is an ID property,
* we look up an IDP PropertyRNA based on the type, and set the data
* pointer to the IDProperty. */
*r_prop_rna_or_id = {};
r_prop_rna_or_id->ptr = ptr;
r_prop_rna_or_id->rawprop = prop;
if (prop->magic == RNA_MAGIC) {
r_prop_rna_or_id->rnaprop = prop;
r_prop_rna_or_id->identifier = prop->identifier;
r_prop_rna_or_id->is_array = prop->getlength || prop->totarraylength;
if (r_prop_rna_or_id->is_array) {
int arraylen[RNA_MAX_ARRAY_DIMENSION];
r_prop_rna_or_id->array_len = (prop->getlength && ptr->data) ?
uint(prop->getlength(ptr, arraylen)) :
prop->totarraylength;
}
if (prop->flag & PROP_IDPROPERTY) {
IDProperty *idprop = rna_system_idproperty_find(ptr, prop->identifier);
if (idprop != nullptr && !rna_idproperty_verify_valid(ptr, prop, idprop)) {
IDProperty *group = RNA_struct_idprops(ptr, false);
IDP_FreeFromGroup(group, idprop);
idprop = nullptr;
}
r_prop_rna_or_id->idprop = idprop;
r_prop_rna_or_id->is_rna_storage_idprop = true;
r_prop_rna_or_id->is_set = idprop != nullptr && (idprop->flag & IDP_FLAG_GHOST) == 0;
}
else {
/* Full static RNA properties are always set. */
r_prop_rna_or_id->is_set = true;
}
}
else {
IDProperty *idprop = (IDProperty *)prop;
/* Given prop may come from the custom properties of another data, ensure we get the one from
* given data ptr. */
IDProperty *idprop_evaluated = rna_idproperty_find(ptr, idprop->name);
if (idprop_evaluated != nullptr && idprop->type != idprop_evaluated->type) {
idprop_evaluated = nullptr;
}
r_prop_rna_or_id->idprop = idprop_evaluated;
r_prop_rna_or_id->is_idprop = true;
/* Full IDProperties are always set, if it exists. */
r_prop_rna_or_id->is_set = (idprop_evaluated != nullptr);
r_prop_rna_or_id->identifier = idprop->name;
if (idprop->type == IDP_ARRAY) {
r_prop_rna_or_id->rnaprop = arraytypemap[int(idprop->subtype)];
r_prop_rna_or_id->is_array = true;
r_prop_rna_or_id->array_len = idprop_evaluated != nullptr ? uint(idprop_evaluated->len) : 0;
}
else {
/* Special case for int properties with enum items, these are displayed as a PROP_ENUM. */
if (idprop->type == IDP_INT) {
const IDPropertyUIDataInt *ui_data_int = reinterpret_cast<IDPropertyUIDataInt *>(
idprop->ui_data);
if (ui_data_int && ui_data_int->enum_items_num > 0) {
r_prop_rna_or_id->rnaprop = &rna_PropertyGroupItem_enum;
return;
}
}
r_prop_rna_or_id->rnaprop = typemap[int(idprop->type)];
}
}
}
IDProperty *rna_idproperty_check(PropertyRNA **prop, PointerRNA *ptr)
{
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(*prop, ptr, &prop_rna_or_id);
*prop = prop_rna_or_id.rnaprop;
return prop_rna_or_id.idprop;
}
PropertyRNA *rna_ensure_property(PropertyRNA *prop)
{
/* the quick version if we don't need the idproperty */
if (prop->magic == RNA_MAGIC) {
return prop;
}
{
IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_ARRAY) {
return arraytypemap[int(idprop->subtype)];
}
/* Special case for int properties with enum items, these are displayed as a PROP_ENUM. */
if (idprop->type == IDP_INT) {
const IDPropertyUIDataInt *ui_data_int = reinterpret_cast<IDPropertyUIDataInt *>(
idprop->ui_data);
if (ui_data_int && ui_data_int->enum_items_num > 0) {
return &rna_PropertyGroupItem_enum;
}
}
return typemap[int(idprop->type)];
}
}
static const char *rna_ensure_property_identifier(const PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
return prop->identifier;
}
return ((const IDProperty *)prop)->name;
}
static const char *rna_ensure_property_description(const PropertyRNA *prop)
{
if (prop->magic == RNA_MAGIC) {
return prop->description;
}
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
const IDPropertyUIData *ui_data = idprop->ui_data;
return ui_data->description;
}
return "";
}
static const char *rna_ensure_property_name(const PropertyRNA *prop)
{
const char *name;
if (prop->magic == RNA_MAGIC) {
name = prop->name;
}
else {
name = ((const IDProperty *)prop)->name;
}
return name;
}
/* Structs */
StructRNA *RNA_struct_find(const char *identifier)
{
return static_cast<StructRNA *>(BLI_ghash_lookup(BLENDER_RNA.structs_map, identifier));
}
const char *RNA_struct_identifier(const StructRNA *type)
{
return type->identifier;
}
const char *RNA_struct_ui_name(const StructRNA *type)
{
return CTX_IFACE_(type->translation_context, type->name);
}
const char *RNA_struct_ui_name_raw(const StructRNA *type)
{
return type->name;
}
int RNA_struct_ui_icon(const StructRNA *type)
{
if (type) {
return type->icon;
}
return ICON_DOT;
}
const char *RNA_struct_ui_description(const StructRNA *type)
{
return TIP_(type->description);
}
const char *RNA_struct_ui_description_raw(const StructRNA *type)
{
return type->description;
}
const char *RNA_struct_translation_context(const StructRNA *type)
{
return type->translation_context;
}
PropertyRNA *RNA_struct_name_property(const StructRNA *type)
{
return type->nameproperty;
}
const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type)
{
return type->prop_tag_defines;
}
PropertyRNA *RNA_struct_iterator_property(StructRNA *type)
{
return type->iteratorproperty;
}
StructRNA *RNA_struct_base(StructRNA *type)
{
return type->base;
}
const StructRNA *RNA_struct_base_child_of(const StructRNA *type, const StructRNA *parent_type)
{
while (type) {
if (type->base == parent_type) {
return type;
}
type = type->base;
}
return nullptr;
}
bool RNA_struct_is_ID(const StructRNA *type)
{
return (type->flag & STRUCT_ID) != 0;
}
bool RNA_struct_undo_check(const StructRNA *type)
{
return (type->flag & STRUCT_UNDO) != 0;
}
bool RNA_struct_idprops_datablock_allowed(const StructRNA *type)
{
return (type->flag & (STRUCT_NO_DATABLOCK_IDPROPERTIES | STRUCT_NO_IDPROPERTIES)) == 0;
}
bool RNA_struct_idprops_contains_datablock(const StructRNA *type)
{
return (type->flag & (STRUCT_CONTAINS_DATABLOCK_IDPROPERTIES | STRUCT_ID)) != 0;
}
bool RNA_struct_system_idprops_register_check(const StructRNA *type)
{
return (type->flag & STRUCT_NO_IDPROPERTIES) == 0 && type->system_idproperties != nullptr;
}
bool RNA_struct_system_idprops_unset(PointerRNA *ptr, const char *identifier)
{
IDProperty *group = RNA_struct_system_idprops(ptr, false);
if (group) {
IDProperty *idp = IDP_GetPropertyFromGroup(group, identifier);
if (idp) {
IDP_FreeFromGroup(group, idp);
return true;
}
}
return false;
}
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
{
const StructRNA *base;
if (srna == &RNA_AnyType) {
return true;
}
if (!type) {
return false;
}
/* ptr->type is always maximally refined */
for (base = type; base; base = base->base) {
if (base == srna) {
return true;
}
}
return false;
}
PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
{
if (identifier[0] == '[' && identifier[1] == '"') {
/* id prop lookup, not so common */
PropertyRNA *r_prop = nullptr;
PointerRNA r_ptr; /* only support single level props */
if (RNA_path_resolve_property(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) &&
(r_ptr.data == ptr->data))
{
return r_prop;
}
}
else {
/* most common case */
PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
PointerRNA propptr;
if (RNA_property_collection_lookup_string(ptr, iterprop, identifier, &propptr)) {
return static_cast<PropertyRNA *>(propptr.data);
}
}
return nullptr;
}
static const char *rna_property_type_identifier(PropertyType prop_type)
{
switch (prop_type) {
case PROP_BOOLEAN:
return RNA_struct_identifier(&RNA_BoolProperty);
case PROP_INT:
return RNA_struct_identifier(&RNA_IntProperty);
case PROP_FLOAT:
return RNA_struct_identifier(&RNA_FloatProperty);
case PROP_STRING:
return RNA_struct_identifier(&RNA_StringProperty);
case PROP_ENUM:
return RNA_struct_identifier(&RNA_EnumProperty);
case PROP_POINTER:
return RNA_struct_identifier(&RNA_PointerProperty);
case PROP_COLLECTION:
return RNA_struct_identifier(&RNA_CollectionProperty);
default:
return RNA_struct_identifier(&RNA_Property);
}
}
PropertyRNA *RNA_struct_find_property_check(PointerRNA &props,
const char *name,
const PropertyType property_type_check)
{
PropertyRNA *prop = RNA_struct_find_property(&props, name);
if (!prop) {
return nullptr;
}
const PropertyType prop_type = RNA_property_type(prop);
if (prop_type == property_type_check) {
return prop;
}
CLOG_WARN(&LOG,
"'%s : %s()' expected, got '%s : %s()'",
name,
rna_property_type_identifier(property_type_check),
name,
rna_property_type_identifier(prop_type));
return nullptr;
}
PropertyRNA *RNA_struct_find_collection_property_check(PointerRNA &props,
const char *name,
const StructRNA *struct_type_check)
{
PropertyRNA *prop = RNA_struct_find_property(&props, name);
if (!prop) {
return nullptr;
}
const PropertyType prop_type = RNA_property_type(prop);
const StructRNA *prop_struct_type = RNA_property_pointer_type(&props, prop);
if (prop_type == PROP_COLLECTION && prop_struct_type == struct_type_check) {
return prop;
}
if (prop_type != PROP_COLLECTION) {
CLOG_WARN(&LOG,
"'%s : %s(type = %s)' expected, got '%s : %s()'",
name,
rna_property_type_identifier(PROP_COLLECTION),
RNA_struct_identifier(struct_type_check),
name,
rna_property_type_identifier(prop_type));
return nullptr;
}
CLOG_WARN(&LOG,
"'%s : %s(type = %s)' expected, got '%s : %s(type = %s)'.",
name,
rna_property_type_identifier(PROP_COLLECTION),
RNA_struct_identifier(struct_type_check),
name,
rna_property_type_identifier(PROP_COLLECTION),
RNA_struct_identifier(prop_struct_type));
return nullptr;
}
PropertyRNA *rna_struct_find_nested(PointerRNA *ptr, StructRNA *srna)
{
PropertyRNA *prop = nullptr;
RNA_STRUCT_BEGIN (ptr, iprop) {
/* This assumes that there can only be one user of this nested struct */
if (RNA_property_pointer_type(ptr, iprop) == srna) {
prop = iprop;
break;
}
}
RNA_PROP_END;
return prop;
}
bool RNA_struct_contains_property(PointerRNA *ptr, PropertyRNA *prop_test)
{
/* NOTE: prop_test could be freed memory, only use for comparison. */
/* validate the RNA is ok */
PropertyRNA *iterprop;
bool found = false;
iterprop = RNA_struct_iterator_property(ptr->type);
RNA_PROP_BEGIN (ptr, itemptr, iterprop) {
// PropertyRNA *prop = itemptr.data;
if (prop_test == (PropertyRNA *)itemptr.data) {
found = true;
break;
}
}
RNA_PROP_END;
return found;
}
uint RNA_struct_count_properties(StructRNA *srna)
{
uint counter = 0;
PointerRNA struct_ptr = RNA_pointer_create_discrete(nullptr, srna, nullptr);
RNA_STRUCT_BEGIN (&struct_ptr, prop) {
counter++;
UNUSED_VARS(prop);
}
RNA_STRUCT_END;
return counter;
}
std::optional<AncestorPointerRNA> RNA_struct_search_closest_ancestor_by_type(PointerRNA *ptr,
const StructRNA *srna)
{
if (RNA_struct_is_a(ptr->type, srna)) {
return {{ptr->type, ptr->data}};
}
else {
for (int i = ptr->ancestors.size() - 1; i >= 0; i--) {
const AncestorPointerRNA &ancestor = ptr->ancestors[i];
if (RNA_struct_is_a(ancestor.type, srna)) {
return ancestor;
}
}
}
return std::nullopt;
}
const ListBase *RNA_struct_type_properties(StructRNA *srna)
{
return &srna->cont.properties;
}
PropertyRNA *RNA_struct_type_find_property_no_base(StructRNA *srna, const char *identifier)
{
return static_cast<PropertyRNA *>(
BLI_findstring_ptr(&srna->cont.properties, identifier, offsetof(PropertyRNA, identifier)));
}
PropertyRNA *RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
{
for (; srna; srna = srna->base) {
PropertyRNA *prop = RNA_struct_type_find_property_no_base(srna, identifier);
if (prop != nullptr) {
return prop;
}
}
return nullptr;
}
FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier)
{
#if 1
FunctionRNA *func;
for (; srna; srna = srna->base) {
func = (FunctionRNA *)BLI_findstring_ptr(
&srna->functions, identifier, offsetof(FunctionRNA, identifier));
if (func) {
return func;
}
}
return nullptr;
/* functional but slow */
#else
PropertyRNA *iterprop;
FunctionRNA *func;
PointerRNA tptr = RNA_pointer_create_discrete(nullptr, &RNA_Struct, srna);
iterprop = RNA_struct_find_property(&tptr, "functions");
func = nullptr;
RNA_PROP_BEGIN (&tptr, funcptr, iterprop) {
if (STREQ(identifier, RNA_function_identifier(funcptr.data))) {
func = funcptr.data;
break;
}
}
RNA_PROP_END;
return func;
#endif
}
const ListBase *RNA_struct_type_functions(StructRNA *srna)
{
return &srna->functions;
}
StructRegisterFunc RNA_struct_register(StructRNA *type)
{
return type->reg;
}
StructUnregisterFunc RNA_struct_unregister(StructRNA *type)
{
do {
if (type->unreg) {
return type->unreg;
}
} while ((type = type->base));
return nullptr;
}
void **RNA_struct_instance(PointerRNA *ptr)
{
StructRNA *type = ptr->type;
do {
if (type->instance) {
return type->instance(ptr);
}
} while ((type = type->base));
return nullptr;
}
void *RNA_struct_py_type_get(StructRNA *srna)
{
return srna->py_type;
}
void RNA_struct_py_type_set(StructRNA *srna, void *py_type)
{
srna->py_type = py_type;
}
void *RNA_struct_blender_type_get(StructRNA *srna)
{
return srna->blender_type;
}
void RNA_struct_blender_type_set(StructRNA *srna, void *blender_type)
{
srna->blender_type = blender_type;
}
char *RNA_struct_name_get_alloc_ex(
PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len, PropertyRNA **r_nameprop)
{
if (ptr->data) {
if (PropertyRNA *nameprop = RNA_struct_name_property(ptr->type)) {
*r_nameprop = nameprop;
return RNA_property_string_get_alloc(ptr, nameprop, fixedbuf, fixedlen, r_len);
}
}
return nullptr;
}
char *RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
{
if (ptr->data) {
if (PropertyRNA *nameprop = RNA_struct_name_property(ptr->type)) {
return RNA_property_string_get_alloc(ptr, nameprop, fixedbuf, fixedlen, r_len);
}
}
return nullptr;
}
bool RNA_struct_available_or_report(ReportList *reports, const char *identifier)
{
const StructRNA *srna_exists = RNA_struct_find(identifier);
if (UNLIKELY(srna_exists != nullptr)) {
/* Use comprehensive string construction since this is such a rare occurrence
* and information here may cut down time troubleshooting. */
DynStr *dynstr = BLI_dynstr_new();
BLI_dynstr_appendf(dynstr, "Type identifier '%s' is already in use: '", identifier);
BLI_dynstr_append(dynstr, srna_exists->identifier);
int i = 0;
if (srna_exists->base) {
for (const StructRNA *base = srna_exists->base; base; base = base->base) {
BLI_dynstr_append(dynstr, "(");
BLI_dynstr_append(dynstr, base->identifier);
i += 1;
}
while (i--) {
BLI_dynstr_append(dynstr, ")");
}
}
BLI_dynstr_append(dynstr, "'.");
char *result = BLI_dynstr_get_cstring(dynstr);
BLI_dynstr_free(dynstr);
BKE_report(reports, RPT_ERROR, result);
MEM_freeN(result);
return false;
}
return true;
}
bool RNA_struct_bl_idname_ok_or_report(ReportList *reports,
const char *identifier,
const char *sep)
{
const int len_sep = strlen(sep);
const int len_id = strlen(identifier);
const char *p = strstr(identifier, sep);
/* TODO: make error, for now warning until add-ons update. */
#if 1
const int report_level = RPT_WARNING;
const bool failure = true;
#else
const int report_level = RPT_ERROR;
const bool failure = false;
#endif
if (p == nullptr || p == identifier || p + len_sep >= identifier + len_id) {
BKE_reportf(reports,
eReportType(report_level),
"'%s' does not contain '%s' with prefix and suffix",
identifier,
sep);
return failure;
}
const char *c, *start, *end, *last;
start = identifier;
end = p;
last = end - 1;
for (c = start; c != end; c++) {
if (((*c >= 'A' && *c <= 'Z') || ((c != start) && (*c >= '0' && *c <= '9')) ||
((c != start) && (c != last) && (*c == '_'))) == 0)
{
BKE_reportf(reports,
eReportType(report_level),
"'%s' doesn't have upper case alpha-numeric prefix",
identifier);
return failure;
}
}
start = p + len_sep;
end = identifier + len_id;
last = end - 1;
for (c = start; c != end; c++) {
if (((*c >= 'A' && *c <= 'Z') || (*c >= 'a' && *c <= 'z') || (*c >= '0' && *c <= '9') ||
((c != start) && (c != last) && (*c == '_'))) == 0)
{
BKE_reportf(reports,
eReportType(report_level),
"'%s' doesn't have an alpha-numeric suffix",
identifier);
return failure;
}
}
return true;
}
/* Property Information */
const char *RNA_property_identifier(const PropertyRNA *prop)
{
return rna_ensure_property_identifier(prop);
}
const char *RNA_property_description(PropertyRNA *prop)
{
return TIP_(rna_ensure_property_description(prop));
}
const DeprecatedRNA *RNA_property_deprecated(const PropertyRNA *prop)
{
return prop->deprecated;
}
PropertyType RNA_property_type(PropertyRNA *prop)
{
return rna_ensure_property(prop)->type;
}
PropertySubType RNA_property_subtype(PropertyRNA *prop)
{
PropertyRNA *rna_prop = rna_ensure_property(prop);
/* For custom properties, find and parse the 'subtype' metadata field. */
if (prop->magic != RNA_MAGIC) {
IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_STRING && idprop->subtype == IDP_STRING_SUB_BYTE) {
return PROP_BYTESTRING;
}
if (idprop->ui_data) {
IDPropertyUIData *ui_data = idprop->ui_data;
return (PropertySubType)ui_data->rna_subtype;
}
}
return rna_prop->subtype;
}
PropertyUnit RNA_property_unit(PropertyRNA *prop)
{
return PropertyUnit(RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)));
}
PropertyScaleType RNA_property_ui_scale(PropertyRNA *prop)
{
PropertyRNA *rna_prop = rna_ensure_property(prop);
switch (rna_prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_prop;
return iprop->ui_scale_type;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_prop;
return fprop->ui_scale_type;
}
default:
return PROP_SCALE_LINEAR;
}
}
int RNA_property_flag(PropertyRNA *prop)
{
return rna_ensure_property(prop)->flag;
}
int RNA_property_tags(PropertyRNA *prop)
{
return rna_ensure_property(prop)->tags;
}
PropertyPathTemplateType RNA_property_path_template_type(PropertyRNA *prop)
{
return rna_ensure_property(prop)->path_template_type;
}
bool RNA_property_builtin(PropertyRNA *prop)
{
return (rna_ensure_property(prop)->flag_internal & PROP_INTERN_BUILTIN) != 0;
}
void *RNA_property_py_data_get(PropertyRNA *prop)
{
/* This is only called in isolated situations (mainly by the Python API),
* so skip check for ID properties. Callers must use #RNA_property_is_idprop
* when it's not known if the property might be an ID Property. */
BLI_assert(prop->magic == RNA_MAGIC);
return prop->py_data;
}
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
{
return rna_ensure_property_array_length(ptr, prop);
}
bool RNA_property_array_check(PropertyRNA *prop)
{
return rna_ensure_property_array_check(prop);
}
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
{
PropertyRNA *rprop = rna_ensure_property(prop);
if (length) {
rna_ensure_property_multi_array_length(ptr, prop, length);
}
return rprop->arraydimension;
}
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension)
{
int len[RNA_MAX_ARRAY_DIMENSION];
rna_ensure_property_multi_array_length(ptr, prop, len);
return len[dimension];
}
char RNA_property_array_item_char(PropertyRNA *prop, int index)
{
const char *vectoritem = "XYZW";
const char *quatitem = "WXYZ";
const char *coloritem = "RGBA";
PropertySubType subtype = RNA_property_subtype(prop);
BLI_assert(index >= 0);
/* get string to use for array index */
if ((index < 4) && ELEM(subtype, PROP_QUATERNION, PROP_AXISANGLE)) {
return quatitem[index];
}
if ((index < 4) && ELEM(subtype,
PROP_TRANSLATION,
PROP_DIRECTION,
PROP_XYZ,
PROP_XYZ_LENGTH,
PROP_EULER,
PROP_VELOCITY,
PROP_ACCELERATION,
PROP_COORDS))
{
return vectoritem[index];
}
if ((index < 4) && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA)) {
return coloritem[index];
}
return '\0';
}
int RNA_property_array_item_index(PropertyRNA *prop, char name)
{
/* Don't use custom property sub-types in RNA path lookup. */
PropertySubType subtype = rna_ensure_property(prop)->subtype;
/* get index based on string name/alias */
/* maybe a function to find char index in string would be better than all the switches */
if (ELEM(subtype, PROP_QUATERNION, PROP_AXISANGLE)) {
switch (name) {
case 'w':
return 0;
case 'x':
return 1;
case 'y':
return 2;
case 'z':
return 3;
}
}
else if (ELEM(subtype,
PROP_TRANSLATION,
PROP_DIRECTION,
PROP_XYZ,
PROP_XYZ_LENGTH,
PROP_EULER,
PROP_VELOCITY,
PROP_ACCELERATION))
{
switch (name) {
case 'x':
return 0;
case 'y':
return 1;
case 'z':
return 2;
case 'w':
return 3;
}
}
else if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA)) {
switch (name) {
case 'r':
return 0;
case 'g':
return 1;
case 'b':
return 2;
case 'a':
return 3;
}
}
return -1;
}
void RNA_property_int_range(PointerRNA *ptr, PropertyRNA *prop, int *hardmin, int *hardmax)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop);
int softmin, softmax;
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->ui_data) {
IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)idprop->ui_data;
*hardmin = ui_data->min;
*hardmax = ui_data->max;
}
else {
*hardmin = INT_MIN;
*hardmax = INT_MAX;
}
return;
}
if (iprop->range) {
*hardmin = INT_MIN;
*hardmax = INT_MAX;
iprop->range(ptr, hardmin, hardmax, &softmin, &softmax);
}
else if (iprop->range_ex) {
*hardmin = INT_MIN;
*hardmax = INT_MAX;
iprop->range_ex(ptr, prop, hardmin, hardmax, &softmin, &softmax);
}
else {
*hardmin = iprop->hardmin;
*hardmax = iprop->hardmax;
}
}
void RNA_property_int_ui_range(
PointerRNA *ptr, PropertyRNA *prop, int *softmin, int *softmax, int *step)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop);
int hardmin, hardmax;
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->ui_data) {
IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)idprop->ui_data;
*softmin = ui_data_int->soft_min;
*softmax = ui_data_int->soft_max;
*step = ui_data_int->step;
}
else {
*softmin = INT_MIN;
*softmax = INT_MAX;
*step = 1;
}
return;
}
*softmin = iprop->softmin;
*softmax = iprop->softmax;
if (iprop->range) {
hardmin = INT_MIN;
hardmax = INT_MAX;
iprop->range(ptr, &hardmin, &hardmax, softmin, softmax);
*softmin = max_ii(*softmin, hardmin);
*softmax = min_ii(*softmax, hardmax);
}
else if (iprop->range_ex) {
hardmin = INT_MIN;
hardmax = INT_MAX;
iprop->range_ex(ptr, prop, &hardmin, &hardmax, softmin, softmax);
*softmin = max_ii(*softmin, hardmin);
*softmax = min_ii(*softmax, hardmax);
}
*step = iprop->step;
}
void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin, float *hardmax)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop);
float softmin, softmax;
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->ui_data) {
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)idprop->ui_data;
*hardmin = float(ui_data->min);
*hardmax = float(ui_data->max);
}
else {
*hardmin = -FLT_MAX;
*hardmax = FLT_MAX;
}
return;
}
if (fprop->range) {
*hardmin = -FLT_MAX;
*hardmax = FLT_MAX;
fprop->range(ptr, hardmin, hardmax, &softmin, &softmax);
}
else if (fprop->range_ex) {
*hardmin = -FLT_MAX;
*hardmax = FLT_MAX;
fprop->range_ex(ptr, prop, hardmin, hardmax, &softmin, &softmax);
}
else {
*hardmin = fprop->hardmin;
*hardmax = fprop->hardmax;
}
}
void RNA_property_float_ui_range(PointerRNA *ptr,
PropertyRNA *prop,
float *softmin,
float *softmax,
float *step,
float *precision)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop);
float hardmin, hardmax;
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->ui_data) {
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)idprop->ui_data;
*softmin = float(ui_data->soft_min);
*softmax = float(ui_data->soft_max);
*step = ui_data->step;
*precision = float(ui_data->precision);
}
else {
*softmin = -FLT_MAX;
*softmax = FLT_MAX;
*step = 1.0f;
*precision = 3.0f;
}
return;
}
*softmin = fprop->softmin;
*softmax = fprop->softmax;
if (fprop->range) {
hardmin = -FLT_MAX;
hardmax = FLT_MAX;
fprop->range(ptr, &hardmin, &hardmax, softmin, softmax);
*softmin = max_ff(*softmin, hardmin);
*softmax = min_ff(*softmax, hardmax);
}
else if (fprop->range_ex) {
hardmin = -FLT_MAX;
hardmax = FLT_MAX;
fprop->range_ex(ptr, prop, &hardmin, &hardmax, softmin, softmax);
*softmin = max_ff(*softmin, hardmin);
*softmax = min_ff(*softmax, hardmax);
}
*step = fprop->step;
*precision = float(fprop->precision);
}
int RNA_property_float_clamp(PointerRNA *ptr, PropertyRNA *prop, float *value)
{
float min, max;
RNA_property_float_range(ptr, prop, &min, &max);
if (*value < min) {
*value = min;
return -1;
}
if (*value > max) {
*value = max;
return 1;
}
return 0;
}
int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value)
{
int min, max;
RNA_property_int_range(ptr, prop, &min, &max);
if (*value < min) {
*value = min;
return -1;
}
if (*value > max) {
*value = max;
return 1;
}
return 0;
}
int RNA_property_string_maxlength(PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
return sprop->maxlength;
}
StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
{
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_ID) {
const IDPropertyUIDataID *ui_data = (const IDPropertyUIDataID *)idprop->ui_data;
if (ui_data) {
return ID_code_to_RNA_type(ui_data->id_type);
}
}
}
prop = rna_ensure_property(prop);
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
if (pprop->type_fn) {
return pprop->type_fn(ptr);
}
if (pprop->type) {
return pprop->type;
}
}
else if (prop->type == PROP_COLLECTION) {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
if (cprop->item_type) {
return cprop->item_type;
}
}
/* ignore other types, rna_struct_find_nested calls with unchecked props */
return &RNA_UnknownType;
}
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value)
{
prop = rna_ensure_property(prop);
if (prop->type != PROP_POINTER) {
printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
return false;
}
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
/* Can't point from linked to local datablock. */
if (ptr->owner_id && value->owner_id && !BKE_id_can_use_id(*ptr->owner_id, *value->owner_id)) {
return false;
}
/* Check custom poll function. */
if (!pprop->poll) {
return true;
}
if (rna_idproperty_check(&prop, ptr)) {
return reinterpret_cast<PropPointerPollFuncPy>(reinterpret_cast<void *>(pprop->poll))(
ptr, *value, prop);
}
return pprop->poll(ptr, *value);
}
void RNA_property_enum_items_ex(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const bool use_static,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
{
if (!use_static && prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (IDProperty *)prop;
if (idprop->type == IDP_INT) {
IDPropertyUIDataInt *ui_data = reinterpret_cast<IDPropertyUIDataInt *>(idprop->ui_data);
int totitem = 0;
EnumPropertyItem *result = nullptr;
if (ui_data) {
for (const IDPropertyUIDataEnumItem &idprop_item :
blender::Span(ui_data->enum_items, ui_data->enum_items_num))
{
BLI_assert(idprop_item.identifier != nullptr);
BLI_assert(idprop_item.name != nullptr);
const EnumPropertyItem item = {idprop_item.value,
idprop_item.identifier,
idprop_item.icon,
idprop_item.name,
idprop_item.description ? idprop_item.description : ""};
RNA_enum_item_add(&result, &totitem, &item);
}
}
RNA_enum_item_end(&result, &totitem);
*r_item = result;
if (r_totitem) {
/* Exclude the terminator item. */
*r_totitem = totitem - 1;
}
*r_free = true;
return;
}
}
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
*r_free = false;
if (!use_static && (eprop->item_fn != nullptr)) {
const bool no_context = (prop->flag & PROP_ENUM_NO_CONTEXT) ||
((ptr->type->flag & STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID) &&
(ptr->owner_id == nullptr));
if (C != nullptr || no_context) {
const EnumPropertyItem *item;
item = eprop->item_fn(no_context ? nullptr : C, ptr, prop, r_free);
/* any callbacks returning nullptr should be fixed */
BLI_assert(item != nullptr);
if (r_totitem) {
int tot;
for (tot = 0; item[tot].identifier; tot++) {
/* pass */
}
*r_totitem = tot;
}
*r_item = item;
return;
}
}
*r_item = eprop->item;
if (r_totitem) {
*r_totitem = eprop->totitem;
}
}
void RNA_property_enum_items(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
{
RNA_property_enum_items_ex(C, ptr, prop, false, r_item, r_totitem, r_free);
}
#ifdef WITH_INTERNATIONAL
static void property_enum_translate(PropertyRNA *prop,
EnumPropertyItem **r_item,
const int *totitem,
bool *r_free)
{
if (!(RNA_property_flag(prop) & PROP_ENUM_NO_TRANSLATE)) {
int i;
/* NOTE: Only do those tests once, and then use BLT_pgettext. */
bool do_iface = BLT_translate_iface();
bool do_tooltip = BLT_translate_tooltips();
EnumPropertyItem *nitem;
if (!(do_iface || do_tooltip)) {
return;
}
if (*r_free) {
nitem = *r_item;
}
else {
const EnumPropertyItem *item = *r_item;
int tot;
if (totitem) {
tot = *totitem;
}
else {
/* count */
for (tot = 0; item[tot].identifier; tot++) {
/* pass */
}
}
nitem = MEM_malloc_arrayN<EnumPropertyItem>(size_t(tot) + 1, __func__);
memcpy(nitem, item, sizeof(EnumPropertyItem) * (tot + 1));
*r_free = true;
}
const char *translation_context = RNA_property_translation_context(prop);
for (i = 0; nitem[i].identifier; i++) {
if (nitem[i].name && do_iface) {
nitem[i].name = BLT_pgettext(translation_context, nitem[i].name);
}
if (nitem[i].description && do_tooltip) {
nitem[i].description = BLT_pgettext(nullptr, nitem[i].description);
}
}
*r_item = nitem;
}
}
#endif
void RNA_property_enum_items_gettexted(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
{
RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free);
#ifdef WITH_INTERNATIONAL
/* Normally dropping 'const' is _not_ ok, in this case it's only modified if we own the memory
* so allow the exception (callers are creating new arrays in this case). */
property_enum_translate(prop, (EnumPropertyItem **)r_item, r_totitem, r_free);
#endif
}
void RNA_property_enum_items_gettexted_all(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
size_t mem_size = sizeof(EnumPropertyItem) * (size_t(eprop->totitem) + 1);
/* first return all items */
EnumPropertyItem *item_array = MEM_malloc_arrayN<EnumPropertyItem>(size_t(eprop->totitem) + 1,
"enum_gettext_all");
*r_free = true;
memcpy(item_array, eprop->item, mem_size);
if (r_totitem) {
*r_totitem = eprop->totitem;
}
if (eprop->item_fn != nullptr) {
const bool no_context = (eprop->property.flag & PROP_ENUM_NO_CONTEXT) ||
((ptr->type->flag & STRUCT_NO_CONTEXT_WITHOUT_OWNER_ID) &&
(ptr->owner_id == nullptr));
if (C != nullptr || no_context) {
const EnumPropertyItem *item;
int i;
bool free = false;
item = eprop->item_fn(no_context ? nullptr : nullptr, ptr, prop, &free);
/* any callbacks returning nullptr should be fixed */
BLI_assert(item != nullptr);
for (i = 0; i < eprop->totitem; i++) {
bool exists = false;
int i_fixed;
/* Items that do not exist on list are returned,
* but have their names/identifiers null'ed out. */
for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) {
if (STREQ(item[i_fixed].identifier, item_array[i].identifier)) {
exists = true;
break;
}
}
if (!exists) {
item_array[i].name = nullptr;
item_array[i].identifier = "";
}
}
if (free) {
MEM_freeN(item);
}
}
}
#ifdef WITH_INTERNATIONAL
property_enum_translate(prop, &item_array, r_totitem, r_free);
#endif
*r_item = item_array;
}
bool RNA_property_enum_value(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value)
{
const EnumPropertyItem *item;
bool free;
bool found;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
if (item) {
const int i = RNA_enum_from_identifier(item, identifier);
if (i != -1) {
*r_value = item[i].value;
found = true;
}
else {
found = false;
}
if (free) {
MEM_freeN(item);
}
}
else {
found = false;
}
return found;
}
bool RNA_enum_identifier(const EnumPropertyItem *item, const int value, const char **r_identifier)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_identifier = item[i].identifier;
return true;
}
return false;
}
int RNA_enum_bitflag_identifiers(const EnumPropertyItem *item,
const int value,
const char **r_identifier)
{
int index = 0;
for (; item->identifier; item++) {
if (item->identifier[0] && item->value & value) {
r_identifier[index++] = item->identifier;
}
}
r_identifier[index] = nullptr;
return index;
}
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_name = item[i].name;
return true;
}
return false;
}
bool RNA_enum_name_gettexted(const EnumPropertyItem *item,
int value,
const char *translation_context,
const char **r_name)
{
bool result;
result = RNA_enum_name(item, value, r_name);
if (result) {
*r_name = BLT_translate_do_iface(translation_context, *r_name);
}
return result;
};
bool RNA_enum_description(const EnumPropertyItem *item,
const int value,
const char **r_description)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_description = item[i].description;
return true;
}
return false;
}
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier)
{
int i = 0;
for (; item->identifier; item++, i++) {
if (item->identifier[0] && STREQ(item->identifier, identifier)) {
return i;
}
}
return -1;
}
bool RNA_enum_value_from_identifier(const EnumPropertyItem *item,
const char *identifier,
int *r_value)
{
const int i = RNA_enum_from_identifier(item, identifier);
if (i == -1) {
return false;
}
*r_value = item[i].value;
return true;
}
int RNA_enum_from_name(const EnumPropertyItem *item, const char *name)
{
int i = 0;
for (; item->identifier; item++, i++) {
if (item->identifier[0] && STREQ(item->name, name)) {
return i;
}
}
return -1;
}
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
{
int i = 0;
for (; item->identifier; item++, i++) {
if (item->identifier[0] && item->value == value) {
return i;
}
}
return -1;
}
uint RNA_enum_items_count(const EnumPropertyItem *item)
{
uint i = 0;
while (item->identifier) {
item++;
i++;
}
return i;
}
bool RNA_property_enum_identifier(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
{
const EnumPropertyItem *item = nullptr;
bool free;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
if (item) {
bool result;
result = RNA_enum_identifier(item, value, r_identifier);
if (free) {
MEM_freeN(item);
}
return result;
}
return false;
}
bool RNA_property_enum_name(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
{
const EnumPropertyItem *item = nullptr;
bool free;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
if (item) {
bool result;
result = RNA_enum_name(item, value, r_name);
if (free) {
MEM_freeN(item);
}
return result;
}
return false;
}
bool RNA_property_enum_name_gettexted(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
{
bool result;
result = RNA_property_enum_name(C, ptr, prop, value, r_name);
if (result) {
if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
*r_name = BLT_translate_do_iface(RNA_property_translation_context(prop), *r_name);
}
}
return result;
}
bool RNA_property_enum_item_from_value(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
{
const EnumPropertyItem *item = nullptr;
bool free;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
if (item) {
const int i = RNA_enum_from_value(item, value);
bool result;
if (i != -1) {
*r_item = item[i];
result = true;
}
else {
result = false;
}
if (free) {
MEM_freeN(item);
}
return result;
}
return false;
}
bool RNA_property_enum_item_from_value_gettexted(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, EnumPropertyItem *r_item)
{
const bool result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item);
if (result && !(RNA_property_flag(prop) & PROP_ENUM_NO_TRANSLATE)) {
r_item->name = BLT_translate_do_iface(RNA_property_translation_context(prop), r_item->name);
r_item->description = BLT_translate_do_tooltip(nullptr, r_item->description);
}
return result;
}
int RNA_property_enum_bitflag_identifiers(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
{
const EnumPropertyItem *item = nullptr;
bool free;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
if (item) {
int result;
result = RNA_enum_bitflag_identifiers(item, value, r_identifier);
if (free) {
MEM_freeN(item);
}
return result;
}
return 0;
}
const char *RNA_property_ui_name(const PropertyRNA *prop)
{
return CTX_IFACE_(RNA_property_translation_context(prop), rna_ensure_property_name(prop));
}
const char *RNA_property_ui_name_raw(const PropertyRNA *prop)
{
return rna_ensure_property_name(prop);
}
const char *RNA_property_ui_description(const PropertyRNA *prop)
{
return TIP_(rna_ensure_property_description(prop));
}
const char *RNA_property_ui_description_raw(const PropertyRNA *prop)
{
return rna_ensure_property_description(prop);
}
const char *RNA_property_translation_context(const PropertyRNA *prop)
{
return rna_ensure_property((PropertyRNA *)prop)->translation_context;
}
int RNA_property_ui_icon(const PropertyRNA *prop)
{
return rna_ensure_property((PropertyRNA *)prop)->icon;
}
static bool rna_property_editable_do(const PointerRNA *ptr,
PropertyRNA *prop_orig,
const int index,
const char **r_info)
{
ID *id = ptr->owner_id;
PropertyRNA *prop = rna_ensure_property(prop_orig);
const char *info = "";
const int flag = (prop->itemeditable != nullptr && index >= 0) ?
prop->itemeditable(ptr, index) :
(prop->editable != nullptr ? prop->editable(ptr, &info) : prop->flag);
if (r_info != nullptr) {
*r_info = info;
}
/* Early return if the property itself is not editable. */
if ((flag & PROP_EDITABLE) == 0) {
return false;
}
/* Only considered registerable properties "internal"
* because regular properties may not be editable and still be displayed. */
if (flag & PROP_REGISTER) {
if (r_info != nullptr && (*r_info)[0] == '\0') {
*r_info = N_("This property is for internal use only and can't be edited");
}
return false;
}
/* If there is no owning ID, the property is editable at this point. */
if (id == nullptr) {
return true;
}
/* Handle linked or liboverride ID cases. */
const bool is_linked_prop_exception = (prop->flag & PROP_LIB_EXCEPTION) != 0;
if (!ID_IS_EDITABLE(id)) {
if (is_linked_prop_exception) {
return true;
}
if (r_info != nullptr && (*r_info)[0] == '\0') {
*r_info = N_("Can't edit this property from a linked data-block");
}
return false;
}
if (ID_IS_OVERRIDE_LIBRARY(id)) {
const bool is_liboverride_system = BKE_lib_override_library_is_system_defined(G_MAIN, id);
if (!RNA_property_overridable_get(ptr, prop_orig)) {
if (r_info != nullptr && (*r_info)[0] == '\0') {
*r_info = N_("Can't edit this property from an override data-block");
}
return false;
}
if (is_liboverride_system && !is_linked_prop_exception) {
if (r_info != nullptr && (*r_info)[0] == '\0') {
*r_info = N_("Can't edit this property from a system override data-block");
}
return false;
}
}
/* At this point, property is owned by a local ID and therefore fully editable. */
return true;
}
bool RNA_property_is_runtime(const PropertyRNA *prop)
{
return prop->flag_internal & PROP_INTERN_RUNTIME;
}
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
{
return rna_property_editable_do(ptr, prop, -1, nullptr);
}
bool RNA_property_editable_info(const PointerRNA *ptr, PropertyRNA *prop, const char **r_info)
{
return rna_property_editable_do(ptr, prop, -1, r_info);
}
bool RNA_property_editable_flag(const PointerRNA *ptr, PropertyRNA *prop)
{
int flag;
const char *dummy_info;
prop = rna_ensure_property(prop);
flag = prop->editable ? prop->editable(ptr, &dummy_info) : prop->flag;
return (flag & PROP_EDITABLE) != 0;
}
bool RNA_property_editable_index(const PointerRNA *ptr, PropertyRNA *prop, const int index)
{
BLI_assert(index >= 0);
return rna_property_editable_do(ptr, prop, index, nullptr);
}
bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop_orig)
{
/* check that base ID-block can support animation data */
if (!id_can_have_animdata(ptr->owner_id)) {
return false;
}
PropertyRNA *prop_ensured = rna_ensure_property(prop_orig);
if (!(prop_ensured->flag & PROP_ANIMATABLE)) {
return false;
}
return true;
}
bool RNA_property_anim_editable(const PointerRNA *ptr, PropertyRNA *prop_orig)
{
/* check that base ID-block can support animation data */
if (!RNA_property_animateable(ptr, prop_orig)) {
return false;
}
/* Linked or LibOverride Action IDs are not editable at the FCurve level. */
if (ptr->owner_id) {
AnimData *anim_data = BKE_animdata_from_id(ptr->owner_id);
if (anim_data && anim_data->action &&
(!ID_IS_EDITABLE(anim_data->action) || ID_IS_OVERRIDE_LIBRARY(anim_data->action)))
{
return false;
}
}
return rna_property_editable_do(ptr, prop_orig, -1, nullptr);
}
bool RNA_property_driver_editable(const PointerRNA *ptr, PropertyRNA *prop)
{
if (!RNA_property_anim_editable(ptr, prop)) {
return false;
}
/* LibOverrides can only get drivers if their animdata (if any) was created for the local
* liboverride, and there is none in the linked reference.
*
* See also #rna_AnimaData_override_apply. */
if (ptr->owner_id && ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) {
IDOverrideLibrary *liboverride = BKE_lib_override_library_get(
nullptr, ptr->owner_id, nullptr, nullptr);
AnimData *linked_reference_anim_data = BKE_animdata_from_id(liboverride->reference);
if (linked_reference_anim_data) {
return false;
}
}
return true;
}
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
{
int len = 1, index;
bool driven, special;
if (!prop) {
return false;
}
if (RNA_property_array_check(prop)) {
len = RNA_property_array_length(ptr, prop);
}
for (index = 0; index < len; index++) {
if (BKE_fcurve_find_by_rna(ptr, prop, index, nullptr, nullptr, &driven, &special)) {
return true;
}
}
return false;
}
bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
{
const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
bool ret = false;
if (path) {
PointerRNA r_ptr;
PropertyRNA *r_prop;
PointerRNA id_ptr = RNA_id_pointer_create(ptr->owner_id);
if (RNA_path_resolve(&id_ptr, path->c_str(), &r_ptr, &r_prop) == true) {
ret = (prop == r_prop);
}
}
return ret;
}
static void rna_property_update(
bContext *C, Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
const bool is_rna = (prop->magic == RNA_MAGIC);
prop = rna_ensure_property(prop);
if (is_rna) {
if (prop->update) {
/* ideally no context would be needed for update, but there's some
* parts of the code that need it still, so we have this exception */
if (prop->flag & PROP_CONTEXT_UPDATE) {
if (C) {
if ((prop->flag & PROP_CONTEXT_PROPERTY_UPDATE) == PROP_CONTEXT_PROPERTY_UPDATE) {
((ContextPropUpdateFunc)prop->update)(C, ptr, prop);
}
else {
reinterpret_cast<ContextUpdateFunc>(reinterpret_cast<void *>(prop->update))(C, ptr);
}
}
}
else {
prop->update(bmain, scene, ptr);
}
}
#if 1
/* TODO(@ideasman42): Should eventually be replaced entirely by message bus (below)
* for now keep since copy-on-eval, bugs are hard to track when we have other missing updates.
*/
if (prop->noteflag) {
WM_main_add_notifier(prop->noteflag, ptr->owner_id);
}
#endif
/* if C is nullptr, we're updating from animation.
* avoid slow-down from f-curves by not publishing (for now). */
if (C != nullptr) {
wmMsgBus *mbus = CTX_wm_message_bus(C);
/* we could add nullptr check, for now don't */
WM_msg_publish_rna(mbus, ptr, prop);
}
if (ptr->owner_id != nullptr && ((prop->flag & PROP_NO_DEG_UPDATE) == 0)) {
const short id_type = GS(ptr->owner_id->name);
if (ID_TYPE_USE_COPY_ON_EVAL(id_type)) {
if (prop->flag & PROP_DEG_SYNC_ONLY) {
DEG_id_tag_update(ptr->owner_id, ID_RECALC_SYNC_TO_EVAL);
}
else {
DEG_id_tag_update(ptr->owner_id, ID_RECALC_SYNC_TO_EVAL | ID_RECALC_PARAMETERS);
}
}
}
/* End message bus. */
}
if (!is_rna || (prop->flag & PROP_IDPROPERTY)) {
/* Disclaimer: this logic is not applied consistently, causing some confusing behavior.
*
* - When animated (which skips update functions).
* - When ID-properties are edited via Python (since RNA properties aren't used in this case).
*
* Adding updates will add a lot of overhead in the case of animation.
* For Python it may cause unexpected slow-downs for developers using ID-properties
* for data storage. Further, the root ID isn't available with nested data-structures.
*
* So editing custom properties only causes updates in the UI,
* keep this exception because it happens to be useful for driving settings.
* Python developers on the other hand will need to manually 'update_tag', see: #74000. */
DEG_id_tag_update(ptr->owner_id,
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_PARAMETERS);
/* When updating an ID pointer property, tag depsgraph for update. */
if (prop->type == PROP_POINTER && RNA_struct_is_ID(RNA_property_pointer_type(ptr, prop))) {
DEG_relations_tag_update(bmain);
}
WM_main_add_notifier(NC_WINDOW, nullptr);
if (ptr->owner_id) {
WM_main_add_notifier(NC_ID | NA_EDITED, nullptr);
}
/* Not nice as well, but the only way to make sure material preview
* is updated with custom nodes.
*/
if ((prop->flag & PROP_IDPROPERTY) != 0 && (ptr->owner_id != nullptr) &&
(GS(ptr->owner_id->name) == ID_NT))
{
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, nullptr);
}
}
}
bool RNA_property_update_check(PropertyRNA *prop)
{
/* NOTE: must keep in sync with #rna_property_update. */
return (prop->magic != RNA_MAGIC || prop->update || prop->noteflag);
}
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
rna_property_update(C, CTX_data_main(C), CTX_data_scene(C), ptr, prop);
}
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
BLI_assert(bmain != nullptr);
rna_property_update(nullptr, bmain, scene, ptr, prop);
}
/* ---------------------------------------------------------------------- */
/* Property Data */
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
bool value;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
value = IDP_Bool(idprop);
}
else if (bprop->get) {
value = bprop->get(ptr);
}
else if (bprop->get_ex) {
value = bprop->get_ex(ptr, prop);
}
else {
value = bprop->defaultvalue;
}
BLI_assert(ELEM(value, false, true));
return value;
}
/**
* The boolean IDProperty type isn't supported in old versions. In order to keep forward
* compatibility for a period of time (until 4.0), save boolean RNA properties as integer
* IDProperties.
*/
#define USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) == false);
BLI_assert(ELEM(value, false, true));
/* just in case other values are passed */
BLI_assert(ELEM(value, true, false));
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDP_Bool(idprop) = value;
rna_idproperty_touch(idprop);
}
else if (bprop->set) {
bprop->set(ptr, value);
}
else if (bprop->set_ex) {
bprop->set_ex(ptr, prop, value);
}
else if (prop->flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
#ifdef USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, int(value), IDP_FLAG_STATIC_TYPE)
.release());
#else
IDP_AddToGroup(
group,
blender::bke::idprop::create_bool(prop->identifier, value, IDP_FLAG_STATIC_TYPE)
.release());
#endif
}
}
}
static void rna_property_boolean_fill_default_array_values(
const bool *defarr, int defarr_length, bool defvalue, int out_length, bool *r_values)
{
if (defarr && defarr_length > 0) {
defarr_length = std::min(defarr_length, out_length);
memcpy(r_values, defarr, sizeof(bool) * defarr_length);
}
else {
defarr_length = 0;
}
for (int i = defarr_length; i < out_length; i++) {
r_values[i] = defvalue;
}
}
static void rna_property_boolean_fill_default_array_values_from_ints(
const int *defarr, int defarr_length, bool defvalue, int out_length, bool *r_values)
{
if (defarr && defarr_length > 0) {
defarr_length = std::min(defarr_length, out_length);
for (int i = 0; i < defarr_length; i++) {
r_values[i] = defarr[i] != 0;
}
}
else {
defarr_length = 0;
}
for (int i = defarr_length; i < out_length; i++) {
r_values[i] = defvalue;
}
}
static void rna_property_boolean_get_default_array_values(PointerRNA *ptr,
BoolPropertyRNA *bprop,
bool *r_values)
{
if (ptr->data && bprop->get_default_array) {
bprop->get_default_array(ptr, &bprop->property, r_values);
return;
}
int length = bprop->property.totarraylength;
int out_length = RNA_property_array_length(ptr, (PropertyRNA *)bprop);
rna_property_boolean_fill_default_array_values(
bprop->defaultarray, length, bprop->defaultvalue, out_length, r_values);
}
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (prop->arraydimension == 0) {
values[0] = RNA_property_boolean_get(ptr, prop);
}
else if (idprop->subtype == IDP_INT) {
/* Some boolean IDProperty arrays might be saved in files as an integer
* array property, since the boolean IDProperty type was added later. */
int *values_src = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values[i] = bool(values_src[i]);
}
}
else if (idprop->subtype == IDP_BOOLEAN) {
bool *values_src = static_cast<bool *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
values[i] = values_src[i];
}
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_boolean_get(ptr, prop);
}
else if (bprop->getarray) {
bprop->getarray(ptr, values);
}
else if (bprop->getarray_ex) {
bprop->getarray_ex(ptr, prop, values);
}
else {
rna_property_boolean_get_default_array_values(ptr, bprop, values);
}
}
void RNA_property_boolean_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
bool *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_boolean_get_array(ptr, prop, values);
return;
}
blender::Array<bool, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_boolean_get_array(ptr, prop, value_buf.data());
memcpy(values, value_buf.data(), sizeof(*values) * values_num);
}
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
bool tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
bool value;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_boolean_get_array(ptr, prop, tmp);
value = tmp[index];
}
else {
bool *tmparray;
tmparray = MEM_malloc_arrayN<bool>(size_t(len), __func__);
RNA_property_boolean_get_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
}
BLI_assert(ELEM(value, false, true));
return value;
}
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (prop->arraydimension == 0) {
IDP_Int(idprop) = values[0];
}
else {
BLI_assert(idprop->type = IDP_ARRAY);
if (idprop->subtype == IDP_BOOLEAN) {
memcpy(IDP_Array(idprop), values, sizeof(int8_t) * idprop->len);
}
else if (idprop->subtype == IDP_INT) {
/* Support writing to integer and boolean IDProperties, since boolean
* RNA properties used to be stored with integer IDProperties. */
int *values_dst = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values_dst[i] = int(values[i]);
}
}
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_boolean_set(ptr, prop, values[0]);
}
else if (bprop->setarray) {
bprop->setarray(ptr, values);
}
else if (bprop->setarray_ex) {
bprop->setarray_ex(ptr, prop, values);
}
else if (prop->flag & PROP_EDITABLE) {
IDPropertyTemplate val = {0};
val.array.len = prop->totarraylength;
#ifdef USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
val.array.type = IDP_INT;
#else
val.array.type = IDP_BOOLEAN;
#endif
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
idprop = IDP_New(IDP_ARRAY, &val, prop->identifier, IDP_FLAG_STATIC_TYPE);
IDP_AddToGroup(group, idprop);
int *values_dst = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values_dst[i] = values[i];
}
}
}
}
void RNA_property_boolean_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const bool *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_boolean_set_array(ptr, prop, values);
return;
}
blender::Array<bool, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_boolean_get_array(ptr, prop, value_buf.data());
memcpy(value_buf.data(), values, sizeof(*values) * values_num);
RNA_property_boolean_set_array(ptr, prop, value_buf.data());
}
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
{
bool tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
BLI_assert(ELEM(value, false, true));
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_boolean_get_array(ptr, prop, tmp);
tmp[index] = value;
RNA_property_boolean_set_array(ptr, prop, tmp);
}
else {
bool *tmparray;
tmparray = MEM_malloc_arrayN<bool>(size_t(len), __func__);
RNA_property_boolean_get_array(ptr, prop, tmparray);
tmparray[index] = value;
RNA_property_boolean_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
}
bool RNA_property_boolean_get_default(PointerRNA *ptr, PropertyRNA *prop)
{
/* TODO: Make defaults work for IDProperties. */
BoolPropertyRNA *bprop = (BoolPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) == false);
BLI_assert(ELEM(bprop->defaultvalue, false, true));
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
switch (IDP_ui_data_type(idprop)) {
case IDP_UI_DATA_TYPE_BOOLEAN: {
const IDPropertyUIDataBool *ui_data = (const IDPropertyUIDataBool *)idprop->ui_data;
return ui_data->default_value;
}
case IDP_UI_DATA_TYPE_INT: {
const IDPropertyUIDataInt *ui_data = (const IDPropertyUIDataInt *)idprop->ui_data;
return ui_data->default_value != 0;
}
default:
BLI_assert_unreachable();
}
}
return false;
}
if (bprop->get_default) {
return bprop->get_default(ptr, prop);
}
return bprop->defaultvalue;
}
void RNA_property_boolean_get_default_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_ARRAY);
switch (IDP_ui_data_type(idprop)) {
case IDP_UI_DATA_TYPE_BOOLEAN: {
const IDPropertyUIDataBool *ui_data = (const IDPropertyUIDataBool *)idprop->ui_data;
if (ui_data->default_array) {
rna_property_boolean_fill_default_array_values((const bool *)ui_data->default_array,
ui_data->default_array_len,
ui_data->default_value,
idprop->len,
values);
}
else {
rna_property_boolean_fill_default_array_values(
nullptr, 0, ui_data->default_value, idprop->len, values);
}
break;
}
case IDP_UI_DATA_TYPE_INT: {
const IDPropertyUIDataInt *ui_data = (const IDPropertyUIDataInt *)idprop->ui_data;
if (ui_data->default_array) {
rna_property_boolean_fill_default_array_values_from_ints(ui_data->default_array,
ui_data->default_array_len,
ui_data->default_value,
idprop->len,
values);
}
else {
rna_property_boolean_fill_default_array_values(
nullptr, 0, ui_data->default_value, idprop->len, values);
}
break;
}
default:
BLI_assert_unreachable();
break;
}
}
}
else if (prop->arraydimension == 0) {
values[0] = bprop->defaultvalue;
}
else {
rna_property_boolean_get_default_array_values(ptr, bprop, values);
}
}
bool RNA_property_boolean_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
bool tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_boolean_get_default_array(ptr, prop, tmp);
return tmp[index];
}
bool *tmparray, value;
tmparray = MEM_malloc_arrayN<bool>(size_t(len), __func__);
RNA_property_boolean_get_default_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
return value;
}
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
return IDP_Int(idprop);
}
if (iprop->get) {
return iprop->get(ptr);
}
if (iprop->get_ex) {
return iprop->get_ex(ptr, prop);
}
return iprop->defaultvalue;
}
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) == false);
/* useful to check on bad values but set function should clamp */
// BLI_assert(RNA_property_int_clamp(ptr, prop, &value) == 0);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
RNA_property_int_clamp(ptr, prop, &value);
IDP_Int(idprop) = value;
rna_idproperty_touch(idprop);
}
else if (iprop->set) {
iprop->set(ptr, value);
}
else if (iprop->set_ex) {
iprop->set_ex(ptr, prop, value);
}
else if (prop->flag & PROP_EDITABLE) {
RNA_property_int_clamp(ptr, prop, &value);
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, value, IDP_FLAG_STATIC_TYPE).release());
}
}
}
static void rna_property_int_fill_default_array_values(
const int *defarr, int defarr_length, int defvalue, int out_length, int *r_values)
{
if (defarr && defarr_length > 0) {
defarr_length = std::min(defarr_length, out_length);
memcpy(r_values, defarr, sizeof(int) * defarr_length);
}
else {
defarr_length = 0;
}
for (int i = defarr_length; i < out_length; i++) {
r_values[i] = defvalue;
}
}
static void rna_property_int_get_default_array_values(PointerRNA *ptr,
IntPropertyRNA *iprop,
int *r_values)
{
if (ptr->data && iprop->get_default_array) {
iprop->get_default_array(ptr, &iprop->property, r_values);
return;
}
int length = iprop->property.totarraylength;
int out_length = RNA_property_array_length(ptr, (PropertyRNA *)iprop);
rna_property_int_fill_default_array_values(
iprop->defaultarray, length, iprop->defaultvalue, out_length, r_values);
}
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
values[0] = RNA_property_int_get(ptr, prop);
}
else {
memcpy(values, IDP_Array(idprop), sizeof(int) * idprop->len);
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_int_get(ptr, prop);
}
else if (iprop->getarray) {
iprop->getarray(ptr, values);
}
else if (iprop->getarray_ex) {
iprop->getarray_ex(ptr, prop, values);
}
else {
rna_property_int_get_default_array_values(ptr, iprop, values);
}
}
void RNA_property_int_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
int *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_int_get_array(ptr, prop, values);
return;
}
blender::Array<int, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_int_get_array(ptr, prop, value_buf.data());
memcpy(values, value_buf.data(), sizeof(*values) * values_num);
}
void RNA_property_int_get_array_range(PointerRNA *ptr, PropertyRNA *prop, int values[2])
{
const int array_len = RNA_property_array_length(ptr, prop);
if (array_len <= 0) {
values[0] = 0;
values[1] = 0;
}
else if (array_len == 1) {
RNA_property_int_get_array(ptr, prop, values);
values[1] = values[0];
}
else {
int arr_stack[32];
int *arr;
int i;
if (array_len > 32) {
arr = MEM_malloc_arrayN<int>(size_t(array_len), __func__);
}
else {
arr = arr_stack;
}
RNA_property_int_get_array(ptr, prop, arr);
values[0] = values[1] = arr[0];
for (i = 1; i < array_len; i++) {
values[0] = std::min(values[0], arr[i]);
values[1] = std::max(values[1], arr[i]);
}
if (arr != arr_stack) {
MEM_freeN(arr);
}
}
}
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
int tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_int_get_array(ptr, prop, tmp);
return tmp[index];
}
int *tmparray, value;
tmparray = MEM_malloc_arrayN<int>(size_t(len), __func__);
RNA_property_int_get_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
return value;
}
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
{
using namespace blender;
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
IDP_Int(idprop) = values[0];
}
else {
memcpy(IDP_Array(idprop), values, sizeof(int) * idprop->len);
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_int_set(ptr, prop, values[0]);
}
else if (iprop->setarray) {
iprop->setarray(ptr, values);
}
else if (iprop->setarray_ex) {
iprop->setarray_ex(ptr, prop, values);
}
else if (prop->flag & PROP_EDITABLE) {
// RNA_property_int_clamp_array(ptr, prop, &value); /* TODO. */
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(group,
bke::idprop::create(prop->identifier,
Span(values, prop->totarraylength),
IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
void RNA_property_int_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const int *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_int_set_array(ptr, prop, values);
return;
}
blender::Array<int, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_int_get_array(ptr, prop, value_buf.data());
memcpy(value_buf.data(), values, sizeof(*values) * values_num);
RNA_property_int_set_array(ptr, prop, value_buf.data());
}
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
{
int tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_int_get_array(ptr, prop, tmp);
tmp[index] = value;
RNA_property_int_set_array(ptr, prop, tmp);
}
else {
int *tmparray;
tmparray = MEM_malloc_arrayN<int>(size_t(len), __func__);
RNA_property_int_get_array(ptr, prop, tmparray);
tmparray[index] = value;
RNA_property_int_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
}
int RNA_property_int_get_default(PointerRNA *ptr, PropertyRNA *prop)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
const IDPropertyUIDataInt *ui_data = (const IDPropertyUIDataInt *)idprop->ui_data;
return ui_data->default_value;
}
}
if (iprop->get_default) {
return iprop->get_default(ptr, prop);
}
return iprop->defaultvalue;
}
bool RNA_property_int_set_default(PropertyRNA *prop, int value)
{
if (prop->magic == RNA_MAGIC) {
return false;
}
IDProperty *idprop = (IDProperty *)prop;
BLI_assert(idprop->type == IDP_INT);
IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(idprop);
ui_data->default_value = value;
return true;
}
void RNA_property_int_get_default_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
if (prop->magic != RNA_MAGIC) {
int length = rna_ensure_property_array_length(ptr, prop);
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_ARRAY);
BLI_assert(idprop->subtype == IDP_INT);
const IDPropertyUIDataInt *ui_data = (const IDPropertyUIDataInt *)idprop->ui_data;
if (ui_data->default_array) {
rna_property_int_fill_default_array_values(ui_data->default_array,
ui_data->default_array_len,
ui_data->default_value,
length,
values);
}
else {
rna_property_int_fill_default_array_values(
nullptr, 0, ui_data->default_value, length, values);
}
}
}
else if (prop->arraydimension == 0) {
values[0] = iprop->defaultvalue;
}
else {
rna_property_int_get_default_array_values(ptr, iprop, values);
}
}
int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
int tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_int_get_default_array(ptr, prop, tmp);
return tmp[index];
}
int *tmparray, value;
tmparray = MEM_malloc_arrayN<int>(size_t(len), __func__);
RNA_property_int_get_default_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
return value;
}
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (idprop->type == IDP_FLOAT) {
return IDP_Float(idprop);
}
return float(IDP_Double(idprop));
}
if (fprop->get) {
return fprop->get(ptr);
}
if (fprop->get_ex) {
return fprop->get_ex(ptr, prop);
}
return fprop->defaultvalue;
}
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) == false);
/* useful to check on bad values but set function should clamp */
// BLI_assert(RNA_property_float_clamp(ptr, prop, &value) == 0);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
RNA_property_float_clamp(ptr, prop, &value);
if (idprop->type == IDP_FLOAT) {
IDP_Float(idprop) = value;
}
else {
IDP_Double(idprop) = value;
}
rna_idproperty_touch(idprop);
}
else if (fprop->set) {
fprop->set(ptr, value);
}
else if (fprop->set_ex) {
fprop->set_ex(ptr, prop, value);
}
else if (prop->flag & PROP_EDITABLE) {
RNA_property_float_clamp(ptr, prop, &value);
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, value, IDP_FLAG_STATIC_TYPE).release());
}
}
}
static void rna_property_float_fill_default_array_values(
const float *defarr, int defarr_length, float defvalue, int out_length, float *r_values)
{
if (defarr && defarr_length > 0) {
defarr_length = std::min(defarr_length, out_length);
memcpy(r_values, defarr, sizeof(float) * defarr_length);
}
else {
defarr_length = 0;
}
for (int i = defarr_length; i < out_length; i++) {
r_values[i] = defvalue;
}
}
/**
* The same logic as #rna_property_float_fill_default_array_values for a double array.
*/
static void rna_property_float_fill_default_array_values_double(const double *default_array,
const int default_array_len,
const double default_value,
const int out_length,
float *r_values)
{
const int array_copy_len = std::min(out_length, default_array_len);
for (int i = 0; i < array_copy_len; i++) {
r_values[i] = float(default_array[i]);
}
for (int i = array_copy_len; i < out_length; i++) {
r_values[i] = float(default_value);
}
}
static void rna_property_float_get_default_array_values(PointerRNA *ptr,
FloatPropertyRNA *fprop,
float *r_values)
{
if (ptr->data && fprop->get_default_array) {
fprop->get_default_array(ptr, &fprop->property, r_values);
return;
}
int length = fprop->property.totarraylength;
int out_length = RNA_property_array_length(ptr, (PropertyRNA *)fprop);
rna_property_float_fill_default_array_values(
fprop->defaultarray, length, fprop->defaultvalue, out_length, r_values);
}
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
int i;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
values[0] = RNA_property_float_get(ptr, prop);
}
else if (idprop->subtype == IDP_FLOAT) {
memcpy(values, IDP_Array(idprop), sizeof(float) * idprop->len);
}
else {
for (i = 0; i < idprop->len; i++) {
values[i] = float(((double *)IDP_Array(idprop))[i]);
}
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_float_get(ptr, prop);
}
else if (fprop->getarray) {
fprop->getarray(ptr, values);
}
else if (fprop->getarray_ex) {
fprop->getarray_ex(ptr, prop, values);
}
else {
rna_property_float_get_default_array_values(ptr, fprop, values);
}
}
void RNA_property_float_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
float *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_float_get_array(ptr, prop, values);
return;
}
blender::Array<float, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_float_get_array(ptr, prop, value_buf.data());
memcpy(values, value_buf.data(), sizeof(*values) * values_num);
}
void RNA_property_float_get_array_range(PointerRNA *ptr, PropertyRNA *prop, float values[2])
{
const int array_len = RNA_property_array_length(ptr, prop);
if (array_len <= 0) {
values[0] = 0.0f;
values[1] = 0.0f;
}
else if (array_len == 1) {
RNA_property_float_get_array(ptr, prop, values);
values[1] = values[0];
}
else {
float arr_stack[32];
float *arr;
int i;
if (array_len > 32) {
arr = MEM_malloc_arrayN<float>(size_t(array_len), __func__);
}
else {
arr = arr_stack;
}
RNA_property_float_get_array(ptr, prop, arr);
values[0] = values[1] = arr[0];
for (i = 1; i < array_len; i++) {
values[0] = std::min(values[0], arr[i]);
values[1] = std::max(values[1], arr[i]);
}
if (arr != arr_stack) {
MEM_freeN(arr);
}
}
}
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
float tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_float_get_array(ptr, prop, tmp);
return tmp[index];
}
float *tmparray, value;
tmparray = MEM_malloc_arrayN<float>(size_t(len), __func__);
RNA_property_float_get_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
return value;
}
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
int i;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
if (idprop->type == IDP_FLOAT) {
IDP_Float(idprop) = values[0];
}
else {
IDP_Double(idprop) = values[0];
}
}
else if (idprop->subtype == IDP_FLOAT) {
memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len);
}
else {
for (i = 0; i < idprop->len; i++) {
((double *)IDP_Array(idprop))[i] = values[i];
}
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_float_set(ptr, prop, values[0]);
}
else if (fprop->setarray) {
fprop->setarray(ptr, values);
}
else if (fprop->setarray_ex) {
fprop->setarray_ex(ptr, prop, values);
}
else if (prop->flag & PROP_EDITABLE) {
// RNA_property_float_clamp_array(ptr, prop, &value); /* TODO. */
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(group,
blender::bke::idprop::create(prop->identifier,
blender::Span(values, prop->totarraylength),
IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
void RNA_property_float_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const float *values,
int values_num)
{
BLI_assert(values_num >= 0);
const int array_num = RNA_property_array_length(ptr, prop);
if (values_num >= array_num) {
RNA_property_float_set_array(ptr, prop, values);
return;
}
blender::Array<float, RNA_STACK_ARRAY> value_buf(array_num);
RNA_property_float_get_array(ptr, prop, value_buf.data());
memcpy(value_buf.data(), values, sizeof(*values) * values_num);
RNA_property_float_set_array(ptr, prop, value_buf.data());
}
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
{
float tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_float_get_array(ptr, prop, tmp);
tmp[index] = value;
RNA_property_float_set_array(ptr, prop, tmp);
}
else {
float *tmparray;
tmparray = MEM_malloc_arrayN<float>(size_t(len), __func__);
RNA_property_float_get_array(ptr, prop, tmparray);
tmparray[index] = value;
RNA_property_float_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
}
float RNA_property_float_get_default(PointerRNA *ptr, PropertyRNA *prop)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) == false);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(ELEM(idprop->type, IDP_FLOAT, IDP_DOUBLE));
const IDPropertyUIDataFloat *ui_data = (const IDPropertyUIDataFloat *)idprop->ui_data;
return float(ui_data->default_value);
}
}
if (fprop->get_default) {
return fprop->get_default(ptr, prop);
}
return fprop->defaultvalue;
}
bool RNA_property_float_set_default(PropertyRNA *prop, float value)
{
if (prop->magic == RNA_MAGIC) {
return false;
}
IDProperty *idprop = (IDProperty *)prop;
BLI_assert(idprop->type == IDP_FLOAT);
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(idprop);
ui_data->default_value = double(value);
return true;
}
void RNA_property_float_get_default_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
if (prop->magic != RNA_MAGIC) {
int length = rna_ensure_property_array_length(ptr, prop);
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_ARRAY);
BLI_assert(ELEM(idprop->subtype, IDP_FLOAT, IDP_DOUBLE));
const IDPropertyUIDataFloat *ui_data = (const IDPropertyUIDataFloat *)idprop->ui_data;
rna_property_float_fill_default_array_values_double(ui_data->default_array,
ui_data->default_array_len,
ui_data->default_value,
length,
values);
}
}
else if (prop->arraydimension == 0) {
values[0] = fprop->defaultvalue;
}
else {
rna_property_float_get_default_array_values(ptr, fprop, values);
}
}
float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index)
{
float tmp[RNA_MAX_ARRAY_LENGTH];
int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
BLI_assert(index >= 0);
BLI_assert(index < len);
if (len <= RNA_MAX_ARRAY_LENGTH) {
RNA_property_float_get_default_array(ptr, prop, tmp);
return tmp[index];
}
float *tmparray, value;
tmparray = MEM_malloc_arrayN<float>(size_t(len), __func__);
RNA_property_float_get_default_array(ptr, prop, tmparray);
value = tmparray[index];
MEM_freeN(tmparray);
return value;
}
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop);
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
const size_t length = size_t(RNA_property_string_length(ptr, prop));
if ((idprop = rna_idproperty_check(&prop, ptr))) {
/* For normal strings, the length does not contain the null terminator. But for
* #IDP_STRING_SUB_BYTE, it contains the full string including any terminating null. */
return std::string{IDP_String(idprop), length};
}
if (!sprop->get && !sprop->get_ex) {
return std::string{sprop->defaultvalue};
}
std::string string_ret{};
/* Note: after `resize()` the underlying buffer is actually at least
* `length + 1` bytes long, because (since C++11) `std::string` guarantees
* a terminating null byte, but that is not considered part of the length. */
string_ret.resize(length);
if (sprop->get) {
sprop->get(ptr, string_ret.data());
}
else { /* if (sprop->get_ex) */
sprop->get_ex(ptr, prop, string_ret.data());
}
return string_ret;
}
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
/* editing bytes is not 100% supported
* since they can contain NIL chars */
if (idprop->subtype == IDP_STRING_SUB_BYTE) {
memcpy(value, IDP_String(idprop), idprop->len);
value[idprop->len] = '\0';
}
else {
memcpy(value, IDP_String(idprop), idprop->len);
}
}
else if (sprop->get) {
sprop->get(ptr, value);
}
else if (sprop->get_ex) {
sprop->get_ex(ptr, prop, value);
}
else {
strcpy(value, sprop->defaultvalue);
}
}
char *RNA_property_string_get_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
{
if (fixedbuf) {
BLI_string_debug_size(fixedbuf, fixedlen);
}
char *buf;
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
length = RNA_property_string_length(ptr, prop);
if (length + 1 < fixedlen) {
buf = fixedbuf;
}
else {
buf = MEM_malloc_arrayN<char>(size_t(length) + 1, __func__);
}
#ifndef NDEBUG
/* safety check to ensure the string is actually set */
buf[length] = 255;
#endif
RNA_property_string_get(ptr, prop, buf);
#ifndef NDEBUG
BLI_assert(buf[length] == '\0');
#endif
if (r_len) {
*r_len = length;
}
return buf;
}
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (idprop->subtype == IDP_STRING_SUB_BYTE) {
return idprop->len;
}
#ifndef NDEBUG
/* these _must_ stay in sync */
BLI_assert(strlen(IDP_String(idprop)) == idprop->len - 1);
#endif
return idprop->len - 1;
}
if (sprop->length) {
return sprop->length(ptr);
}
if (sprop->length_ex) {
return sprop->length_ex(ptr, prop);
}
return strlen(sprop->defaultvalue);
}
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
/* both IDP_STRING_SUB_BYTE / IDP_STRING_SUB_UTF8 */
IDP_AssignStringMaxSize(idprop, value, RNA_property_string_maxlength(prop));
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDP_AddToGroup(
group,
IDP_NewStringMaxSize(
value, RNA_property_string_maxlength(prop), prop->identifier, IDP_FLAG_STATIC_TYPE));
}
}
}
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
BLI_assert(RNA_property_subtype(prop) == PROP_BYTESTRING);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDP_ResizeArray(idprop, len);
memcpy(idprop->data.pointer, value, size_t(len));
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
/* XXX, should take length argument (currently not used). */
sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
/* XXX, should take length argument (currently not used). */
sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDPropertyTemplate val = {0};
val.string.str = value;
val.string.len = len;
val.string.subtype = IDP_STRING_SUB_BYTE;
IDP_AddToGroup(group, IDP_New(IDP_STRING, &val, prop->identifier, IDP_FLAG_STATIC_TYPE));
}
}
}
void RNA_property_string_get_default(PropertyRNA *prop, char *value, const int value_maxncpy)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_STRING);
const IDPropertyUIDataString *ui_data = (const IDPropertyUIDataString *)idprop->ui_data;
BLI_strncpy(value, ui_data->default_value, value_maxncpy);
return;
}
strcpy(value, "");
return;
}
BLI_assert(RNA_property_type(prop) == PROP_STRING);
strcpy(value, sprop->defaultvalue);
}
char *RNA_property_string_get_default_alloc(
PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
{
char *buf;
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
length = RNA_property_string_default_length(ptr, prop);
if (length + 1 < fixedlen) {
buf = fixedbuf;
}
else {
buf = MEM_calloc_arrayN<char>(size_t(length) + 1, __func__);
}
RNA_property_string_get_default(prop, buf, length + 1);
if (r_len) {
*r_len = length;
}
return buf;
}
int RNA_property_string_default_length(PointerRNA * /*ptr*/, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = (const IDProperty *)prop;
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_STRING);
const IDPropertyUIDataString *ui_data = (const IDPropertyUIDataString *)idprop->ui_data;
if (ui_data->default_value != nullptr) {
return strlen(ui_data->default_value);
}
}
return 0;
}
BLI_assert(RNA_property_type(prop) == PROP_STRING);
return strlen(sprop->defaultvalue);
}
eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
if (prop->magic != RNA_MAGIC) {
return eStringPropertySearchFlag(0);
}
BLI_assert(RNA_property_type(prop) == PROP_STRING);
if (sprop->search) {
BLI_assert(sprop->search_flag & PROP_STRING_SEARCH_SUPPORTED);
}
else {
BLI_assert(sprop->search_flag == 0);
}
return sprop->search_flag;
}
void RNA_property_string_search(
const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
const char *edit_text,
blender::FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
BLI_assert(RNA_property_string_search_flag(prop) & PROP_STRING_SEARCH_SUPPORTED);
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_ensure_property(prop);
sprop->search(C, ptr, prop, edit_text, visit_fn);
}
std::optional<std::string> RNA_property_string_path_filter(const bContext *C,
PointerRNA *ptr,
PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_STRING);
PropertyRNA *rna_prop = rna_ensure_property(prop);
StringPropertyRNA *sprop = (StringPropertyRNA *)rna_prop;
if (!sprop->path_filter) {
return std::nullopt;
}
return sprop->path_filter(C, ptr, rna_prop);
}
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
return IDP_Int(idprop);
}
if (eprop->get) {
return eprop->get(ptr);
}
if (eprop->get_ex) {
return eprop->get_ex(ptr, prop);
}
return eprop->defaultvalue;
}
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDP_Int(idprop) = value;
rna_idproperty_touch(idprop);
}
else if (eprop->set) {
eprop->set(ptr, value);
}
else if (eprop->set_ex) {
eprop->set_ex(ptr, prop, value);
}
else if (prop->flag & PROP_EDITABLE) {
IDPropertyTemplate val = {0};
IDProperty *group;
val.i = value;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDP_AddToGroup(group, IDP_New(IDP_INT, &val, prop->identifier, IDP_FLAG_STATIC_TYPE));
}
}
}
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
if (prop->magic != RNA_MAGIC) {
const IDProperty *idprop = reinterpret_cast<const IDProperty *>(prop);
if (idprop->ui_data) {
BLI_assert(idprop->type == IDP_INT);
const IDPropertyUIDataInt *ui_data = reinterpret_cast<const IDPropertyUIDataInt *>(
idprop->ui_data);
return ui_data->default_value;
}
}
if (eprop->get_default) {
return eprop->get_default(ptr, prop);
}
return eprop->defaultvalue;
}
int RNA_property_enum_step(
const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
{
const EnumPropertyItem *item_array;
int totitem;
bool free;
int result_value = from_value;
int i, i_init;
int single_step = (step < 0) ? -1 : 1;
int step_tot = 0;
RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
i = RNA_enum_from_value(item_array, from_value);
i_init = i;
do {
i = mod_i(i + single_step, totitem);
if (item_array[i].identifier[0]) {
step_tot += single_step;
}
} while ((i != i_init) && (step_tot != step));
if (i != i_init) {
result_value = item_array[i].value;
}
if (free) {
MEM_freeN(item_array);
}
return result_value;
}
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
IDProperty *idprop;
static blender::Mutex mutex;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
pprop = (PointerPropertyRNA *)prop;
if (RNA_struct_is_ID(pprop->type)) {
/* ID PointerRNA should not have ancestors currently. */
return RNA_id_pointer_create(IDP_Id(idprop));
}
/* for groups, data is idprop itself */
if (pprop->type_fn) {
return RNA_pointer_create_with_parent(*ptr, pprop->type_fn(ptr), idprop);
}
return RNA_pointer_create_with_parent(*ptr, pprop->type, idprop);
}
if (pprop->get) {
return pprop->get(ptr);
}
if (prop->flag & PROP_IDPROPERTY) {
/* NOTE: While creating/writing data in an accessor is really bad design-wise, this is
* currently very difficult to avoid in that case. So a global mutex is used to keep ensuring
* thread safety. */
std::scoped_lock lock(mutex);
/* NOTE: We do not need to check again for existence of the pointer after locking here, since
* this is also done in #RNA_property_pointer_add itself. */
RNA_property_pointer_add(ptr, prop);
return RNA_property_pointer_get(ptr, prop);
}
return PointerRNA_NULL;
}
void RNA_property_pointer_set(PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA ptr_value,
ReportList *reports)
{
/* Detect IDProperty and retrieve the actual PropertyRNA pointer before cast. */
IDProperty *idprop = rna_idproperty_check(&prop, ptr);
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
/* This is a 'real' RNA property, not an IDProperty or a dynamic RNA property using an IDProperty
* as backend storage. */
if (pprop->set) {
if (ptr_value.type != nullptr && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
BKE_reportf(reports,
RPT_ERROR,
"%s: expected %s type, not %s",
__func__,
pprop->type->identifier,
ptr_value.type->identifier);
return;
}
if (!((prop->flag & PROP_NEVER_NULL) && ptr_value.data == nullptr) &&
!((prop->flag & PROP_ID_SELF_CHECK) && ptr->owner_id == ptr_value.owner_id))
{
pprop->set(ptr, ptr_value, reports);
}
return;
}
/* Assigning to an IDProperty. */
ID *value = static_cast<ID *>(ptr_value.data);
if (ptr_value.type != nullptr && !RNA_struct_is_a(ptr_value.type, &RNA_ID)) {
BKE_reportf(
reports, RPT_ERROR, "%s: expected ID type, not %s", __func__, ptr_value.type->identifier);
return;
}
if (value && (value->flag & ID_FLAG_EMBEDDED_DATA) != 0) {
BKE_reportf(reports, RPT_ERROR, "%s: cannot assign an embedded ID to an IDProperty", __func__);
return;
}
/* We got an existing IDProperty. */
if (idprop != nullptr) {
/* Not-yet-defined ID IDProps have an IDP_GROUP type, not an IDP_ID one - because of reasons?
* XXX This has to be investigated fully - there might be a good reason for it, but off hands
* this seems really weird... */
if (idprop->type == IDP_ID) {
IDP_AssignID(idprop, value, 0);
rna_idproperty_touch(idprop);
}
else {
BLI_assert(idprop->type == IDP_GROUP);
IDProperty *group = RNA_struct_system_idprops(ptr, true);
BLI_assert(group != nullptr);
IDP_ReplaceInGroup_ex(
group,
blender::bke::idprop::create(idprop->name, value, IDP_FLAG_STATIC_TYPE).release(),
idprop,
0);
}
}
/* IDProperty disguised as RNA property (and not yet defined in ptr). */
else if (prop->flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_ReplaceInGroup(
group,
blender::bke::idprop::create(prop->identifier, value, IDP_FLAG_STATIC_TYPE).release());
}
}
}
PointerRNA RNA_property_pointer_get_default(PointerRNA * /*ptr*/, PropertyRNA * /*prop*/)
{
// PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
// BLI_assert(RNA_property_type(prop) == PROP_POINTER);
return PointerRNA_NULL; /* FIXME: there has to be a way... */
}
void RNA_property_pointer_add(PointerRNA *ptr, PropertyRNA *prop)
{
// IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
if (/*idprop=*/rna_idproperty_check(&prop, ptr)) {
/* already exists */
}
else if (prop->flag & PROP_IDPROPERTY) {
IDProperty *group;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDP_AddToGroup(
group,
blender::bke::idprop::create_group(prop->identifier, IDP_FLAG_STATIC_TYPE).release());
}
}
else {
printf("%s %s.%s: only supported for id properties.\n",
__func__,
ptr->type->identifier,
prop->identifier);
}
}
void RNA_property_pointer_remove(PointerRNA *ptr, PropertyRNA *prop)
{
IDProperty *idprop, *group;
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
group = RNA_struct_system_idprops(ptr, false);
if (group) {
IDP_FreeFromGroup(group, idprop);
}
}
else {
printf("%s %s.%s: only supported for id properties.\n",
__func__,
ptr->type->identifier,
prop->identifier);
}
}
static void rna_property_collection_get_idp(CollectionPropertyIterator *iter)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)iter->prop;
rna_pointer_create_with_ancestors(
iter->parent, cprop->item_type, rna_iterator_array_get(iter), iter->ptr);
}
void RNA_property_collection_begin(PointerRNA *ptr,
PropertyRNA *prop,
CollectionPropertyIterator *iter)
{
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
*iter = {};
if ((idprop = rna_idproperty_check(&prop, ptr)) || (prop->flag & PROP_IDPROPERTY)) {
iter->parent = *ptr;
iter->prop = prop;
if (idprop) {
rna_iterator_array_begin(
iter, ptr, IDP_IDPArray(idprop), sizeof(IDProperty), idprop->len, false, nullptr);
}
else {
rna_iterator_array_begin(iter, ptr, nullptr, sizeof(IDProperty), 0, false, nullptr);
}
if (iter->valid) {
rna_property_collection_get_idp(iter);
}
iter->idprop = 1;
}
else {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
cprop->begin(iter, ptr);
}
}
void RNA_property_collection_next(CollectionPropertyIterator *iter)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop);
if (iter->idprop) {
rna_iterator_array_next(iter);
if (iter->valid) {
rna_property_collection_get_idp(iter);
}
}
else {
cprop->next(iter);
}
}
void RNA_property_collection_skip(CollectionPropertyIterator *iter, int num)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop);
int i;
if (num > 1 && (iter->idprop || (cprop->property.flag_internal & PROP_INTERN_RAW_ARRAY))) {
/* fast skip for array */
ArrayIterator *internal = &iter->internal.array;
if (!internal->skip) {
internal->ptr += internal->itemsize * (num - 1);
iter->valid = (internal->ptr < internal->endptr);
if (iter->valid) {
RNA_property_collection_next(iter);
}
return;
}
}
/* slow iteration otherwise */
for (i = 0; i < num && iter->valid; i++) {
RNA_property_collection_next(iter);
}
}
void RNA_property_collection_end(CollectionPropertyIterator *iter)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop);
if (iter->idprop) {
rna_iterator_array_end(iter);
}
else {
cprop->end(iter);
}
}
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
return idprop->len;
}
if (cprop->length) {
return cprop->length(ptr);
}
CollectionPropertyIterator iter;
int length = 0;
RNA_property_collection_begin(ptr, prop, &iter);
for (; iter.valid; RNA_property_collection_next(&iter)) {
length++;
}
RNA_property_collection_end(&iter);
return length;
}
bool RNA_property_collection_is_empty(PointerRNA *ptr, PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
CollectionPropertyIterator iter;
RNA_property_collection_begin(ptr, prop, &iter);
bool test = iter.valid;
RNA_property_collection_end(&iter);
return !test;
}
/* This helper checks whether given collection property itself is editable (we only currently
* support a limited set of operations, insertion of new items, and re-ordering of those new items
* exclusively). */
static bool property_collection_liboverride_editable(PointerRNA *ptr,
PropertyRNA *prop,
bool *r_is_liboverride)
{
ID *id = ptr->owner_id;
if (id == nullptr) {
*r_is_liboverride = false;
return true;
}
const bool is_liboverride = *r_is_liboverride = ID_IS_OVERRIDE_LIBRARY(id);
if (!is_liboverride) {
/* We return True also for linked data, as it allows tricks like py scripts 'overriding' data
* of those. */
return true;
}
if (!RNA_property_overridable_get(ptr, prop)) {
return false;
}
if (prop->magic != RNA_MAGIC || (prop->flag & PROP_IDPROPERTY) == 0) {
/* Insertion and such not supported for pure IDProperties for now, nor for pure RNA/DNA ones.
*/
return false;
}
if ((prop->flag_override & PROPOVERRIDE_LIBRARY_INSERTION) == 0) {
return false;
}
/* No more checks to do, this collections is overridable. */
return true;
}
void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
{
IDProperty *idprop;
// CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
bool is_liboverride;
if (!property_collection_liboverride_editable(ptr, prop, &is_liboverride)) {
if (r_ptr) {
*r_ptr = {};
}
return;
}
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDProperty *item;
item = blender::bke::idprop::create_group("", IDP_FLAG_STATIC_TYPE).release();
if (is_liboverride) {
item->flag |= IDP_FLAG_OVERRIDELIBRARY_LOCAL;
}
IDP_AppendArray(idprop, item);
/* IDP_AppendArray does a shallow copy (memcpy), only free memory. */
// IDP_FreePropertyContent(item);
MEM_freeN(item);
rna_idproperty_touch(idprop);
}
else if (prop->flag & PROP_IDPROPERTY) {
IDProperty *group, *item;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
idprop = IDP_NewIDPArray(prop->identifier);
IDP_AddToGroup(group, idprop);
item = blender::bke::idprop::create_group("", IDP_FLAG_STATIC_TYPE).release();
if (is_liboverride) {
item->flag |= IDP_FLAG_OVERRIDELIBRARY_LOCAL;
}
IDP_AppendArray(idprop, item);
/* #IDP_AppendArray does a shallow copy (memcpy), only free memory. */
// IDP_FreePropertyContent(item);
MEM_freeN(item);
}
}
if (r_ptr) {
if (idprop) {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
rna_pointer_create_with_ancestors(
*ptr, cprop->item_type, IDP_GetIndexArray(idprop, idprop->len - 1), *r_ptr);
}
else {
*r_ptr = {};
}
}
}
bool RNA_property_collection_remove(PointerRNA *ptr, PropertyRNA *prop, int key)
{
IDProperty *idprop;
// CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
bool is_liboverride;
if (!property_collection_liboverride_editable(ptr, prop, &is_liboverride)) {
return false;
}
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDProperty tmp, *array;
int len;
len = idprop->len;
array = IDP_IDPArray(idprop);
if (key >= 0 && key < len) {
if (is_liboverride && (array[key].flag & IDP_FLAG_OVERRIDELIBRARY_LOCAL) == 0) {
/* We can only remove items that we actually inserted in the local override. */
return false;
}
if (key + 1 < len) {
/* move element to be removed to the back */
memcpy(&tmp, &array[key], sizeof(IDProperty));
memmove(array + key, array + key + 1, sizeof(IDProperty) * (len - (key + 1)));
memcpy(&array[len - 1], &tmp, sizeof(IDProperty));
}
IDP_ResizeIDPArray(idprop, len - 1);
}
return true;
}
if (prop->flag & PROP_IDPROPERTY) {
return true;
}
return false;
}
bool RNA_property_collection_move(PointerRNA *ptr, PropertyRNA *prop, int key, int pos)
{
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
bool is_liboverride;
if (!property_collection_liboverride_editable(ptr, prop, &is_liboverride)) {
return false;
}
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDProperty tmp, *array;
int len;
len = idprop->len;
array = IDP_IDPArray(idprop);
if (key >= 0 && key < len && pos >= 0 && pos < len && key != pos) {
if (is_liboverride && (array[key].flag & IDP_FLAG_OVERRIDELIBRARY_LOCAL) == 0) {
/* We can only move items that we actually inserted in the local override. */
return false;
}
memcpy(&tmp, &array[key], sizeof(IDProperty));
if (pos < key) {
memmove(array + pos + 1, array + pos, sizeof(IDProperty) * (key - pos));
}
else {
memmove(array + key, array + key + 1, sizeof(IDProperty) * (pos - key));
}
memcpy(&array[pos], &tmp, sizeof(IDProperty));
}
return true;
}
if (prop->flag & PROP_IDPROPERTY) {
return true;
}
return false;
}
void RNA_property_collection_clear(PointerRNA *ptr, PropertyRNA *prop)
{
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
bool is_liboverride;
if (!property_collection_liboverride_editable(ptr, prop, &is_liboverride)) {
return;
}
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (is_liboverride) {
/* We can only move items that we actually inserted in the local override. */
int len = idprop->len;
IDProperty tmp, *array = IDP_IDPArray(idprop);
for (int i = 0; i < len; i++) {
if ((array[i].flag & IDP_FLAG_OVERRIDELIBRARY_LOCAL) != 0) {
memcpy(&tmp, &array[i], sizeof(IDProperty));
memmove(array + i, array + i + 1, sizeof(IDProperty) * (len - (i + 1)));
memcpy(&array[len - 1], &tmp, sizeof(IDProperty));
IDP_ResizeIDPArray(idprop, --len);
i--;
}
}
}
else {
IDP_ResizeIDPArray(idprop, 0);
}
rna_idproperty_touch(idprop);
}
}
int RNA_property_collection_lookup_index(PointerRNA *ptr,
PropertyRNA *prop,
const PointerRNA *t_ptr)
{
CollectionPropertyIterator iter;
int index = 0;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
RNA_property_collection_begin(ptr, prop, &iter);
for (index = 0; iter.valid; RNA_property_collection_next(&iter), index++) {
if (iter.ptr.data == t_ptr->data) {
break;
}
}
RNA_property_collection_end(&iter);
/* did we find it? */
if (iter.valid) {
return index;
}
return -1;
}
bool RNA_property_collection_lookup_int_has_fn(PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
return cprop->lookupint != nullptr;
}
bool RNA_property_collection_lookup_string_has_fn(PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
return cprop->lookupstring != nullptr;
}
bool RNA_property_collection_lookup_string_has_nameprop(PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
return (cprop->item_type && cprop->item_type->nameproperty);
}
bool RNA_property_collection_lookup_string_supported(PropertyRNA *prop)
{
return (RNA_property_collection_lookup_string_has_fn(prop) ||
RNA_property_collection_lookup_string_has_nameprop(prop));
}
bool RNA_property_collection_lookup_int(PointerRNA *ptr,
PropertyRNA *prop,
int key,
PointerRNA *r_ptr)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
if (cprop->lookupint) {
/* we have a callback defined, use it */
return cprop->lookupint(ptr, key, r_ptr);
}
/* no callback defined, just iterate and find the nth item */
CollectionPropertyIterator iter;
int i;
RNA_property_collection_begin(ptr, prop, &iter);
for (i = 0; iter.valid; RNA_property_collection_next(&iter), i++) {
if (i == key) {
*r_ptr = iter.ptr;
break;
}
}
RNA_property_collection_end(&iter);
if (!iter.valid) {
*r_ptr = {};
}
return iter.valid;
}
bool RNA_property_collection_lookup_string_index(
PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr, int *r_index)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
if (!key) {
*r_index = -1;
*r_ptr = PointerRNA_NULL;
return false;
}
if (cprop->lookupstring) {
/* we have a callback defined, use it */
return cprop->lookupstring(ptr, key, r_ptr);
}
/* no callback defined, compare with name properties if they exist */
CollectionPropertyIterator iter;
PropertyRNA *nameprop;
char name_buf[256], *name;
bool found = false;
int keylen = strlen(key);
int namelen;
int index = 0;
RNA_property_collection_begin(ptr, prop, &iter);
for (; iter.valid; RNA_property_collection_next(&iter), index++) {
if (iter.ptr.data && iter.ptr.type->nameproperty) {
nameprop = iter.ptr.type->nameproperty;
name = RNA_property_string_get_alloc(
&iter.ptr, nameprop, name_buf, sizeof(name_buf), &namelen);
if ((keylen == namelen) && STREQ(name, key)) {
*r_ptr = iter.ptr;
found = true;
}
if (name != name_buf) {
MEM_freeN(name);
}
if (found) {
break;
}
}
}
RNA_property_collection_end(&iter);
if (!iter.valid) {
*r_ptr = {};
*r_index = -1;
}
else {
*r_index = index;
}
return iter.valid;
}
bool RNA_property_collection_lookup_string(PointerRNA *ptr,
PropertyRNA *prop,
const char *key,
PointerRNA *r_ptr)
{
int index;
return RNA_property_collection_lookup_string_index(ptr, prop, key, r_ptr, &index);
}
bool RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
const int key,
const PointerRNA *assign_ptr)
{
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(prop);
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
if (cprop->assignint) {
/* we have a callback defined, use it */
return cprop->assignint(ptr, key, assign_ptr);
}
return false;
}
bool RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr)
{
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
*r_ptr = *ptr;
return ((r_ptr->type = rna_ensure_property(prop)->srna) ? 1 : 0);
}
int RNA_property_collection_raw_array(
PointerRNA *ptr, PropertyRNA *prop, PropertyRNA *itemprop, bool set, RawArray *array)
{
CollectionPropertyIterator iter;
ArrayIterator *internal;
char *arrayp;
BLI_assert(RNA_property_type(prop) == PROP_COLLECTION);
if (!(prop->flag_internal & PROP_INTERN_RAW_ARRAY) ||
!(itemprop->flag_internal & PROP_INTERN_RAW_ACCESS))
{
return 0;
}
RNA_property_collection_begin(ptr, prop, &iter);
if (iter.valid) {
/* get data from array iterator and item property */
internal = &iter.internal.array;
arrayp = (iter.valid) ? static_cast<char *>(iter.ptr.data) : nullptr;
if (internal->skip || (set && !RNA_property_editable(&iter.ptr, itemprop))) {
/* we might skip some items, so it's not a proper array */
RNA_property_collection_end(&iter);
return 0;
}
array->array = arrayp + itemprop->rawoffset;
array->stride = internal->itemsize;
array->len = ((char *)internal->endptr - arrayp) / internal->itemsize;
array->type = itemprop->rawtype;
}
else {
memset(array, 0, sizeof(RawArray));
}
RNA_property_collection_end(&iter);
return 1;
}
#define RAW_GET(dtype, var, raw, a) \
{ \
switch (raw.type) { \
case PROP_RAW_CHAR: \
var = (dtype)((char *)raw.array)[a]; \
break; \
case PROP_RAW_INT8: \
var = (dtype)((int8_t *)raw.array)[a]; \
break; \
case PROP_RAW_UINT8: \
var = (dtype)((uint8_t *)raw.array)[a]; \
break; \
case PROP_RAW_SHORT: \
var = (dtype)((short *)raw.array)[a]; \
break; \
case PROP_RAW_UINT16: \
var = (dtype)((uint16_t *)raw.array)[a]; \
break; \
case PROP_RAW_INT: \
var = (dtype)((int *)raw.array)[a]; \
break; \
case PROP_RAW_BOOLEAN: \
var = (dtype)((bool *)raw.array)[a]; \
break; \
case PROP_RAW_FLOAT: \
var = (dtype)((float *)raw.array)[a]; \
break; \
case PROP_RAW_DOUBLE: \
var = (dtype)((double *)raw.array)[a]; \
break; \
case PROP_RAW_INT64: \
var = (dtype)((int64_t *)raw.array)[a]; \
break; \
case PROP_RAW_UINT64: \
var = (dtype)((uint64_t *)raw.array)[a]; \
break; \
default: \
var = (dtype)0; \
} \
} \
(void)0
#define RAW_SET(dtype, raw, a, var) \
{ \
switch (raw.type) { \
case PROP_RAW_CHAR: \
((char *)raw.array)[a] = char(var); \
break; \
case PROP_RAW_INT8: \
((int8_t *)raw.array)[a] = int8_t(var); \
break; \
case PROP_RAW_UINT8: \
((uint8_t *)raw.array)[a] = uint8_t(var); \
break; \
case PROP_RAW_SHORT: \
((short *)raw.array)[a] = short(var); \
break; \
case PROP_RAW_UINT16: \
((uint16_t *)raw.array)[a] = uint16_t(var); \
break; \
case PROP_RAW_INT: \
((int *)raw.array)[a] = int(var); \
break; \
case PROP_RAW_BOOLEAN: \
((bool *)raw.array)[a] = bool(var); \
break; \
case PROP_RAW_FLOAT: \
((float *)raw.array)[a] = float(var); \
break; \
case PROP_RAW_DOUBLE: \
((double *)raw.array)[a] = double(var); \
break; \
case PROP_RAW_INT64: \
((int64_t *)raw.array)[a] = int64_t(var); \
break; \
case PROP_RAW_UINT64: \
((uint64_t *)raw.array)[a] = uint64_t(var); \
break; \
default: \
break; \
} \
} \
(void)0
size_t RNA_raw_type_sizeof(RawPropertyType type)
{
switch (type) {
case PROP_RAW_CHAR:
return sizeof(char);
case PROP_RAW_INT8:
return sizeof(int8_t);
case PROP_RAW_UINT8:
return sizeof(uint8_t);
case PROP_RAW_SHORT:
return sizeof(short);
case PROP_RAW_UINT16:
return sizeof(uint16_t);
case PROP_RAW_INT:
return sizeof(int);
case PROP_RAW_BOOLEAN:
return sizeof(bool);
case PROP_RAW_FLOAT:
return sizeof(float);
case PROP_RAW_DOUBLE:
return sizeof(double);
case PROP_RAW_INT64:
return sizeof(int64_t);
case PROP_RAW_UINT64:
return sizeof(uint64_t);
default:
return 0;
}
}
static int rna_property_array_length_all_dimensions(PointerRNA *ptr, PropertyRNA *prop)
{
int i, len[RNA_MAX_ARRAY_DIMENSION];
const int dim = RNA_property_array_dimension(ptr, prop, len);
int size;
if (dim == 0) {
return 0;
}
for (size = 1, i = 0; i < dim; i++) {
size *= len[i];
}
return size;
}
static int rna_raw_access(ReportList *reports,
PointerRNA *ptr,
PropertyRNA *prop,
const char *propname,
void *inarray,
RawPropertyType intype,
int inlen,
int set)
{
StructRNA *ptype;
PropertyRNA *itemprop, *iprop;
PropertyType itemtype = PropertyType(0);
RawArray in;
/* Actual array length. Will always be `0` for non-array properties. */
int array_len = 0;
/* Item length. Will always be `1` for non-array properties. */
int item_len = 0;
/* Whether the accessed property is an array or not. */
bool is_array;
/* initialize in array, stride assumed 0 in following code */
in.array = inarray;
in.type = intype;
in.len = inlen;
in.stride = 0;
ptype = RNA_property_pointer_type(ptr, prop);
/* try to get item property pointer */
PointerRNA itemptr_base = RNA_pointer_create_discrete(nullptr, ptype, nullptr);
itemprop = RNA_struct_find_property(&itemptr_base, propname);
if (itemprop) {
/* we have item property pointer */
RawArray out;
/* check type */
itemtype = RNA_property_type(itemprop);
is_array = RNA_property_array_check(itemprop);
if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
BKE_report(reports, RPT_ERROR, "Only boolean, int, float, and enum properties supported");
return 0;
}
/* check item array */
array_len = RNA_property_array_length(&itemptr_base, itemprop);
item_len = is_array ? array_len : 1;
/* dynamic array? need to get length per item */
if (itemprop->getlength) {
itemprop = nullptr;
}
/* try to access as raw array */
else if (RNA_property_collection_raw_array(ptr, prop, itemprop, set, &out)) {
if (in.len != item_len * out.len) {
BKE_reportf(reports,
RPT_ERROR,
"Array length mismatch (expected %d, got %d)",
out.len * item_len,
in.len);
return 0;
}
/* matching raw types */
if (out.type == in.type) {
void *inp = in.array;
void *outp = out.array;
size_t size;
size = RNA_raw_type_sizeof(out.type) * item_len;
if (size == out.stride) {
/* The property is stored contiguously so the entire array can be copied at once. */
if (set) {
memcpy(outp, inp, size * out.len);
}
else {
memcpy(inp, outp, size * out.len);
}
}
else {
for (int a = 0; a < out.len; a++) {
if (set) {
memcpy(outp, inp, size);
}
else {
memcpy(inp, outp, size);
}
inp = (char *)inp + size;
outp = (char *)outp + out.stride;
}
}
return 1;
}
/* Could also be faster with non-matching types,
* for now we just do slower loop. */
}
BLI_assert_msg(array_len == 0 || itemtype != PROP_ENUM,
"Enum array properties should not exist");
}
{
void *tmparray = nullptr;
int tmplen = 0;
int err = 0, j, a = 0;
int needconv = 1;
if (((itemtype == PROP_INT) && (in.type == PROP_RAW_INT)) ||
((itemtype == PROP_BOOLEAN) && (in.type == PROP_RAW_BOOLEAN)) ||
((itemtype == PROP_FLOAT) && (in.type == PROP_RAW_FLOAT)))
{
/* avoid creating temporary buffer if the data type match */
needconv = 0;
}
/* no item property pointer, can still be id property, or
* property of a type derived from the collection pointer type */
RNA_PROP_BEGIN (ptr, itemptr, prop) {
if (itemptr.data) {
if (itemprop) {
/* we got the property already */
iprop = itemprop;
}
else {
/* not yet, look it up and verify if it is valid */
iprop = RNA_struct_find_property(&itemptr, propname);
if (iprop) {
is_array = RNA_property_array_check(iprop);
array_len = rna_property_array_length_all_dimensions(&itemptr, iprop);
item_len = is_array ? array_len : 1;
itemtype = RNA_property_type(iprop);
}
else {
BKE_reportf(reports, RPT_ERROR, "Property named '%s' not found", propname);
err = 1;
break;
}
if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
BKE_report(
reports, RPT_ERROR, "Only boolean, int, float and enum properties supported");
err = 1;
break;
}
BLI_assert_msg(array_len == 0 || itemtype != PROP_ENUM,
"Enum array properties should not exist");
}
/* editable check */
if (!set || RNA_property_editable(&itemptr, iprop)) {
if (a + item_len > in.len) {
BKE_reportf(
reports, RPT_ERROR, "Array length mismatch (got %d, expected more)", in.len);
err = 1;
break;
}
if (array_len == 0) {
/* handle conversions */
if (set) {
switch (itemtype) {
case PROP_BOOLEAN: {
int b;
RAW_GET(bool, b, in, a);
RNA_property_boolean_set(&itemptr, iprop, b);
break;
}
case PROP_INT: {
int i;
RAW_GET(int, i, in, a);
RNA_property_int_set(&itemptr, iprop, i);
break;
}
case PROP_FLOAT: {
float f;
RAW_GET(float, f, in, a);
RNA_property_float_set(&itemptr, iprop, f);
break;
}
case PROP_ENUM: {
int i;
RAW_GET(int, i, in, a);
RNA_property_enum_set(&itemptr, iprop, i);
break;
}
default:
BLI_assert_unreachable();
break;
}
}
else {
switch (itemtype) {
case PROP_BOOLEAN: {
int b = RNA_property_boolean_get(&itemptr, iprop);
RAW_SET(bool, in, a, b);
break;
}
case PROP_INT: {
int i = RNA_property_int_get(&itemptr, iprop);
RAW_SET(int, in, a, i);
break;
}
case PROP_FLOAT: {
float f = RNA_property_float_get(&itemptr, iprop);
RAW_SET(float, in, a, f);
break;
}
case PROP_ENUM: {
int i = RNA_property_enum_get(&itemptr, iprop);
RAW_SET(int, in, a, i);
break;
}
default:
BLI_assert_unreachable();
break;
}
}
a++;
}
else if (needconv == 1) {
/* allocate temporary array if needed */
if (tmparray && tmplen != array_len) {
MEM_freeN(tmparray);
tmparray = nullptr;
}
if (!tmparray) {
tmparray = MEM_calloc_arrayN<float>(array_len, "RNA tmparray");
tmplen = array_len;
}
/* handle conversions */
if (set) {
switch (itemtype) {
case PROP_BOOLEAN: {
bool *array = static_cast<bool *>(tmparray);
for (j = 0; j < array_len; j++, a++) {
RAW_GET(bool, array[j], in, a);
}
RNA_property_boolean_set_array(&itemptr, iprop, array);
break;
}
case PROP_INT: {
int *array = static_cast<int *>(tmparray);
for (j = 0; j < array_len; j++, a++) {
RAW_GET(int, array[j], in, a);
}
RNA_property_int_set_array(&itemptr, iprop, array);
break;
}
case PROP_FLOAT: {
float *array = static_cast<float *>(tmparray);
for (j = 0; j < array_len; j++, a++) {
RAW_GET(float, array[j], in, a);
}
RNA_property_float_set_array(&itemptr, iprop, array);
break;
}
default:
BLI_assert_unreachable();
break;
}
}
else {
switch (itemtype) {
case PROP_BOOLEAN: {
bool *array = static_cast<bool *>(tmparray);
RNA_property_boolean_get_array(&itemptr, iprop, array);
for (j = 0; j < array_len; j++, a++) {
RAW_SET(int, in, a, ((bool *)tmparray)[j]);
}
break;
}
case PROP_INT: {
int *array = static_cast<int *>(tmparray);
RNA_property_int_get_array(&itemptr, iprop, array);
for (j = 0; j < array_len; j++, a++) {
RAW_SET(int, in, a, array[j]);
}
break;
}
case PROP_FLOAT: {
float *array = static_cast<float *>(tmparray);
RNA_property_float_get_array(&itemptr, iprop, array);
for (j = 0; j < array_len; j++, a++) {
RAW_SET(float, in, a, array[j]);
}
break;
}
default:
BLI_assert_unreachable();
break;
}
}
}
else {
if (set) {
switch (itemtype) {
case PROP_BOOLEAN: {
RNA_property_boolean_set_array(&itemptr, iprop, &((bool *)in.array)[a]);
a += array_len;
break;
}
case PROP_INT: {
RNA_property_int_set_array(&itemptr, iprop, &((int *)in.array)[a]);
a += array_len;
break;
}
case PROP_FLOAT: {
RNA_property_float_set_array(&itemptr, iprop, &((float *)in.array)[a]);
a += array_len;
break;
}
default:
BLI_assert_unreachable();
break;
}
}
else {
switch (itemtype) {
case PROP_BOOLEAN: {
RNA_property_boolean_get_array(&itemptr, iprop, &((bool *)in.array)[a]);
a += array_len;
break;
}
case PROP_INT: {
RNA_property_int_get_array(&itemptr, iprop, &((int *)in.array)[a]);
a += array_len;
break;
}
case PROP_FLOAT: {
RNA_property_float_get_array(&itemptr, iprop, &((float *)in.array)[a]);
a += array_len;
break;
}
default:
BLI_assert_unreachable();
break;
}
}
}
}
}
}
RNA_PROP_END;
if (tmparray) {
MEM_freeN(tmparray);
}
return !err;
}
}
RawPropertyType RNA_property_raw_type(PropertyRNA *prop)
{
if (prop->rawtype == PROP_RAW_UNSET) {
/* this property has no raw access,
* yet we try to provide a raw type to help building the array. */
switch (prop->type) {
case PROP_BOOLEAN:
return PROP_RAW_BOOLEAN;
case PROP_INT:
return PROP_RAW_INT;
case PROP_FLOAT:
return PROP_RAW_FLOAT;
case PROP_ENUM:
return PROP_RAW_INT;
default:
break;
}
}
return prop->rawtype;
}
int RNA_property_collection_raw_get(ReportList *reports,
PointerRNA *ptr,
PropertyRNA *prop,
const char *propname,
void *array,
RawPropertyType type,
int len)
{
return rna_raw_access(reports, ptr, prop, propname, array, type, len, 0);
}
int RNA_property_collection_raw_set(ReportList *reports,
PointerRNA *ptr,
PropertyRNA *prop,
const char *propname,
void *array,
RawPropertyType type,
int len)
{
return rna_raw_access(reports, ptr, prop, propname, array, type, len, 1);
}
/* Standard iterator functions */
void rna_iterator_listbase_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr,
ListBase *lb,
IteratorSkipFunc skip)
{
iter->parent = *ptr;
ListBaseIterator *internal = &iter->internal.listbase;
internal->link = (lb) ? static_cast<Link *>(lb->first) : nullptr;
internal->skip = skip;
iter->valid = (internal->link != nullptr);
if (skip && iter->valid && skip(iter, internal->link)) {
rna_iterator_listbase_next(iter);
}
}
void rna_iterator_listbase_next(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
if (internal->skip) {
do {
internal->link = internal->link->next;
iter->valid = (internal->link != nullptr);
} while (iter->valid && internal->skip(iter, internal->link));
}
else {
internal->link = internal->link->next;
iter->valid = (internal->link != nullptr);
}
}
void *rna_iterator_listbase_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
return internal->link;
}
void rna_iterator_listbase_end(CollectionPropertyIterator * /*iter*/) {}
PointerRNA rna_listbase_lookup_int(PointerRNA *ptr, StructRNA *type, ListBase *lb, int index)
{
void *data = BLI_findlink(lb, index);
return RNA_pointer_create_with_parent(*ptr, type, data);
}
void rna_iterator_array_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr,
void *data,
size_t itemsize,
int64_t length,
bool free_ptr,
IteratorSkipFunc skip)
{
iter->parent = *ptr;
ArrayIterator *internal;
if (data == nullptr) {
length = 0;
}
else if (length == 0) {
data = nullptr;
itemsize = 0;
}
else if (UNLIKELY(length < 0 || length > std::numeric_limits<uint64_t>::max() / itemsize)) {
/* This path is never expected to execute. Assert and trace if it ever does. */
BLI_assert_unreachable();
data = nullptr;
length = 0;
}
internal = &iter->internal.array;
internal->ptr = static_cast<char *>(data);
internal->free_ptr = free_ptr ? data : nullptr;
internal->endptr = ((char *)data) + itemsize * length;
internal->itemsize = itemsize;
internal->skip = skip;
internal->length = length;
iter->valid = (internal->ptr != internal->endptr);
if (skip && iter->valid && skip(iter, internal->ptr)) {
rna_iterator_array_next(iter);
}
}
void rna_iterator_array_next(CollectionPropertyIterator *iter)
{
ArrayIterator *internal = &iter->internal.array;
if (internal->skip) {
do {
internal->ptr += internal->itemsize;
iter->valid = (internal->ptr != internal->endptr);
} while (iter->valid && internal->skip(iter, internal->ptr));
}
else {
internal->ptr += internal->itemsize;
iter->valid = (internal->ptr != internal->endptr);
}
}
void *rna_iterator_array_get(CollectionPropertyIterator *iter)
{
ArrayIterator *internal = &iter->internal.array;
return internal->ptr;
}
void *rna_iterator_array_dereference_get(CollectionPropertyIterator *iter)
{
ArrayIterator *internal = &iter->internal.array;
/* for ** arrays */
return *(void **)(internal->ptr);
}
void rna_iterator_array_end(CollectionPropertyIterator *iter)
{
ArrayIterator *internal = &iter->internal.array;
MEM_SAFE_FREE(internal->free_ptr);
}
PointerRNA rna_array_lookup_int(
PointerRNA *ptr, StructRNA *type, void *data, size_t itemsize, int64_t length, int64_t index)
{
if (index < 0 || index >= length) {
return PointerRNA_NULL;
}
if (UNLIKELY(index > std::numeric_limits<uint64_t>::max() / itemsize)) {
/* This path is never expected to execute. Assert and trace if it ever does. */
BLI_assert_unreachable();
return PointerRNA_NULL;
}
return RNA_pointer_create_with_parent(*ptr, type, ((char *)data) + itemsize * index);
}
/* Quick name based property access */
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_boolean_get(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return false;
}
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_boolean_set(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_boolean_get_array(PointerRNA *ptr, const char *name, bool *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_boolean_get_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_boolean_set_array(PointerRNA *ptr, const char *name, const bool *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_boolean_set_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
int RNA_int_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_int_get(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return 0;
}
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_int_set(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_int_get_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_int_set_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
float RNA_float_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_float_get(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return 0;
}
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_float_set(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_float_get_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_float_set_array(ptr, prop, values);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
int RNA_enum_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_enum_get(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return 0;
}
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_enum_set(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_enum_set_identifier(bContext *C, PointerRNA *ptr, const char *name, const char *id)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
int value;
if (RNA_property_enum_value(C, ptr, prop, id, &value)) {
RNA_property_enum_set(ptr, prop, value);
}
else {
printf("%s: %s.%s has no enum id '%s'.\n", __func__, ptr->type->identifier, name, id);
}
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
bool RNA_enum_is_equal(bContext *C, PointerRNA *ptr, const char *name, const char *enumname)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
const EnumPropertyItem *item;
bool free;
if (prop) {
int i;
bool cmp = false;
RNA_property_enum_items(C, ptr, prop, &item, nullptr, &free);
i = RNA_enum_from_identifier(item, enumname);
if (i != -1) {
cmp = (item[i].value == RNA_property_enum_get(ptr, prop));
}
if (free) {
MEM_freeN(item);
}
if (i != -1) {
return cmp;
}
printf("%s: %s.%s item %s not found.\n", __func__, ptr->type->identifier, name, enumname);
return false;
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return false;
}
bool RNA_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value)
{
const int i = RNA_enum_from_identifier(item, identifier);
if (i != -1) {
*r_value = item[i].value;
return true;
}
return false;
}
bool RNA_enum_id_from_value(const EnumPropertyItem *item, int value, const char **r_identifier)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_identifier = item[i].identifier;
return true;
}
return false;
}
bool RNA_enum_icon_from_value(const EnumPropertyItem *item, int value, int *r_icon)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_icon = item[i].icon;
return true;
}
return false;
}
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
{
const int i = RNA_enum_from_value(item, value);
if (i != -1) {
*r_name = item[i].name;
return true;
}
return false;
}
std::string RNA_string_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (!prop) {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return {};
}
return RNA_property_string_get(ptr, prop);
}
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_string_get(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
value[0] = '\0';
}
}
char *RNA_string_get_alloc(
PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_string_get_alloc(ptr, prop, fixedbuf, fixedlen, r_len);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
if (r_len != nullptr) {
*r_len = 0;
}
return nullptr;
}
int RNA_string_length(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_string_length(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return 0;
}
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_string_set(ptr, prop, value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_pointer_get(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return PointerRNA_NULL;
}
void RNA_pointer_set(PointerRNA *ptr, const char *name, PointerRNA ptr_value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_pointer_set(ptr, prop, ptr_value, nullptr);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_pointer_add(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_pointer_add(ptr, prop);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_collection_begin(PointerRNA *ptr, const char *name, CollectionPropertyIterator *iter)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_collection_begin(ptr, prop, iter);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_collection_add(ptr, prop, r_value);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
void RNA_collection_clear(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
RNA_property_collection_clear(ptr, prop);
}
else {
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
}
int RNA_collection_length(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_collection_length(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return 0;
}
bool RNA_collection_is_empty(PointerRNA *ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
return RNA_property_collection_is_empty(ptr, prop);
}
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return false;
}
bool RNA_property_is_set_ex(PointerRNA *ptr, PropertyRNA *prop, bool use_ghost)
{
prop = rna_ensure_property(prop);
if (prop->flag & PROP_IDPROPERTY) {
IDProperty *idprop = rna_system_idproperty_find(ptr, prop->identifier);
return ((idprop != nullptr) && (use_ghost == false || !(idprop->flag & IDP_FLAG_GHOST)));
}
return true;
}
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
{
prop = rna_ensure_property(prop);
if (prop->flag & PROP_IDPROPERTY) {
IDProperty *idprop = rna_system_idproperty_find(ptr, prop->identifier);
return ((idprop != nullptr) && !(idprop->flag & IDP_FLAG_GHOST));
}
return true;
}
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
{
prop = rna_ensure_property(prop);
if (prop->flag & PROP_IDPROPERTY) {
rna_system_idproperty_free(ptr, prop->identifier);
}
}
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, identifier);
if (prop) {
return RNA_property_is_set_ex(ptr, prop, use_ghost);
}
/* python raises an error */
// printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return false;
}
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, identifier);
if (prop) {
return RNA_property_is_set(ptr, prop);
}
/* python raises an error */
// printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
return false;
}
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, identifier);
if (prop) {
RNA_property_unset(ptr, prop);
}
}
bool RNA_property_is_idprop(const PropertyRNA *prop)
{
return (prop->magic != RNA_MAGIC);
}
bool RNA_property_is_unlink(PropertyRNA *prop)
{
const int flag = RNA_property_flag(prop);
if (RNA_property_type(prop) == PROP_STRING) {
return (flag & PROP_NEVER_UNLINK) == 0;
}
return (flag & (PROP_NEVER_UNLINK | PROP_NEVER_NULL)) == 0;
}
std::string RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
{
std::stringstream ss;
const char *propname;
int first_time = 1;
ss << '{';
RNA_STRUCT_BEGIN (ptr, prop) {
propname = RNA_property_identifier(prop);
if (STREQ(propname, "rna_type")) {
continue;
}
if (first_time == 0) {
ss << ", ";
}
first_time = 0;
const std::string str = RNA_property_as_string(C, ptr, prop, -1, INT_MAX);
ss << fmt::format("\"{}\":{}", propname, str);
}
RNA_STRUCT_END;
ss << '}';
return ss.str();
}
static std::optional<std::string> rna_pointer_as_string__bldata(PointerRNA *ptr)
{
if (ptr->type == nullptr || ptr->owner_id == nullptr) {
return "None";
}
if (RNA_struct_is_ID(ptr->type)) {
return RNA_path_full_ID_py(ptr->owner_id);
}
return RNA_path_full_struct_py(ptr);
}
std::optional<std::string> RNA_pointer_as_string(bContext *C,
PointerRNA *ptr,
PropertyRNA *prop_ptr,
PointerRNA *ptr_prop)
{
IDProperty *prop;
if (ptr_prop->data == nullptr) {
return "None";
}
if ((prop = rna_idproperty_check(&prop_ptr, ptr)) && prop->type != IDP_ID) {
return RNA_pointer_as_string_id(C, ptr_prop);
}
return rna_pointer_as_string__bldata(ptr_prop);
}
std::string RNA_pointer_as_string_keywords_ex(bContext *C,
PointerRNA *ptr,
const bool as_function,
const bool all_args,
const bool nested_args,
const int max_prop_length,
PropertyRNA *iterprop)
{
const char *arg_name = nullptr;
PropertyRNA *prop;
std::stringstream ss;
bool first_iter = true;
int flag, flag_parameter;
RNA_PROP_BEGIN (ptr, propptr, iterprop) {
prop = static_cast<PropertyRNA *>(propptr.data);
flag = RNA_property_flag(prop);
flag_parameter = RNA_parameter_flag(prop);
if (as_function && (flag_parameter & PARM_OUTPUT)) {
continue;
}
arg_name = RNA_property_identifier(prop);
if (STREQ(arg_name, "rna_type")) {
continue;
}
if ((nested_args == false) && (RNA_property_type(prop) == PROP_POINTER)) {
continue;
}
if (as_function && (prop->flag_parameter & PARM_REQUIRED)) {
/* required args don't have useful defaults */
ss << fmt::format(fmt::runtime(first_iter ? "{}" : ", {}"), arg_name);
first_iter = false;
}
else {
bool ok = true;
if (all_args == true) {
/* pass */
}
else if (RNA_struct_system_idprops_check(ptr->type)) {
ok = RNA_property_is_set(ptr, prop);
}
if (ok) {
std::string buf;
if (as_function && RNA_property_type(prop) == PROP_POINTER) {
/* don't expand pointers for functions */
if (flag & PROP_NEVER_NULL) {
/* we can't really do the right thing here. arg=arg?, hrmf! */
buf = arg_name;
}
else {
buf = "None";
}
}
else {
buf = RNA_property_as_string(C, ptr, prop, -1, max_prop_length);
}
ss << fmt::format(fmt::runtime(first_iter ? "{}={}" : ", {}={}"), arg_name, buf);
first_iter = false;
}
}
}
RNA_PROP_END;
return ss.str();
}
std::string RNA_pointer_as_string_keywords(bContext *C,
PointerRNA *ptr,
const bool as_function,
const bool all_args,
const bool nested_args,
const int max_prop_length)
{
PropertyRNA *iterprop;
iterprop = RNA_struct_iterator_property(ptr->type);
return RNA_pointer_as_string_keywords_ex(
C, ptr, as_function, all_args, nested_args, max_prop_length, iterprop);
}
std::string RNA_function_as_string_keywords(bContext *C,
FunctionRNA *func,
const bool as_function,
const bool all_args,
const int max_prop_length)
{
PointerRNA funcptr = RNA_pointer_create_discrete(nullptr, &RNA_Function, func);
PropertyRNA *iterprop = RNA_struct_find_property(&funcptr, "parameters");
RNA_struct_iterator_property(funcptr.type);
return RNA_pointer_as_string_keywords_ex(
C, &funcptr, as_function, all_args, true, max_prop_length, iterprop);
}
static const char *bool_as_py_string(const int var)
{
return var ? "True" : "False";
}
static void *rna_array_as_string_alloc(
int type, int len, PointerRNA *ptr, PropertyRNA *prop, void **r_buf_end)
{
switch (type) {
case PROP_BOOLEAN: {
bool *buf = MEM_malloc_arrayN<bool>(size_t(len), __func__);
RNA_property_boolean_get_array(ptr, prop, buf);
*r_buf_end = buf + len;
return buf;
}
case PROP_INT: {
int *buf = MEM_malloc_arrayN<int>(size_t(len), __func__);
RNA_property_int_get_array(ptr, prop, buf);
*r_buf_end = buf + len;
return buf;
}
case PROP_FLOAT: {
float *buf = MEM_malloc_arrayN<float>(size_t(len), __func__);
RNA_property_float_get_array(ptr, prop, buf);
*r_buf_end = buf + len;
return buf;
}
default:
BLI_assert_unreachable();
return nullptr;
}
}
static void rna_array_as_string_elem(int type, void **buf_p, int len, std::stringstream &ss)
{
/* This will print a comma separated string of the array elements from
* buf start to len. We will add a comma if len == 1 to preserve tuples. */
const int end = len - 1;
switch (type) {
case PROP_BOOLEAN: {
bool *buf = static_cast<bool *>(*buf_p);
for (int i = 0; i < len; i++, buf++) {
ss << fmt::format(fmt::runtime((i < end || !end) ? "{}, " : "{}"),
bool_as_py_string(*buf));
}
*buf_p = buf;
break;
}
case PROP_INT: {
int *buf = static_cast<int *>(*buf_p);
for (int i = 0; i < len; i++, buf++) {
ss << fmt::format(fmt::runtime((i < end || !end) ? "{}, " : "{}"), *buf);
}
*buf_p = buf;
break;
}
case PROP_FLOAT: {
float *buf = static_cast<float *>(*buf_p);
for (int i = 0; i < len; i++, buf++) {
ss << fmt::format(fmt::runtime((i < end || !end) ? "{:g}, " : "{:g}"), *buf);
}
*buf_p = buf;
break;
}
default:
BLI_assert_unreachable();
}
}
static void rna_array_as_string_recursive(
int type, void **buf_p, int totdim, const int *dim_size, std::stringstream &ss)
{
ss << '(';
if (totdim > 1) {
totdim--;
const int end = dim_size[totdim] - 1;
for (int i = 0; i <= end; i++) {
rna_array_as_string_recursive(type, buf_p, totdim, dim_size, ss);
if (i < end || !end) {
ss << ", ";
}
}
}
else {
rna_array_as_string_elem(type, buf_p, dim_size[0], ss);
}
ss << ')';
}
static void rna_array_as_string(
int type, int len, PointerRNA *ptr, PropertyRNA *prop, std::stringstream &ss)
{
void *buf_end;
void *buf = rna_array_as_string_alloc(type, len, ptr, prop, &buf_end);
void *buf_step = buf;
int totdim, dim_size[RNA_MAX_ARRAY_DIMENSION];
totdim = RNA_property_array_dimension(ptr, prop, dim_size);
rna_array_as_string_recursive(type, &buf_step, totdim, dim_size, ss);
BLI_assert(buf_step == buf_end);
MEM_freeN(buf);
}
std::string RNA_property_as_string(
bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index, int max_prop_length)
{
int type = RNA_property_type(prop);
int len = RNA_property_array_length(ptr, prop);
std::stringstream ss;
/* see if we can coerce into a python type - PropertyType */
switch (type) {
case PROP_BOOLEAN:
if (len == 0) {
ss << bool_as_py_string(RNA_property_boolean_get(ptr, prop));
}
else {
if (index != -1) {
ss << bool_as_py_string(RNA_property_boolean_get_index(ptr, prop, index));
}
else {
rna_array_as_string(type, len, ptr, prop, ss);
}
}
break;
case PROP_INT:
if (len == 0) {
ss << RNA_property_int_get(ptr, prop);
}
else {
if (index != -1) {
ss << RNA_property_int_get_index(ptr, prop, index);
}
else {
rna_array_as_string(type, len, ptr, prop, ss);
}
}
break;
case PROP_FLOAT:
if (len == 0) {
ss << fmt::format("{:g}", RNA_property_float_get(ptr, prop));
}
else {
if (index != -1) {
ss << fmt::format("{:g}", RNA_property_float_get_index(ptr, prop, index));
}
else {
rna_array_as_string(type, len, ptr, prop, ss);
}
}
break;
case PROP_STRING: {
char *buf_esc;
char *buf;
int length;
length = RNA_property_string_length(ptr, prop);
buf = MEM_malloc_arrayN<char>(size_t(length) + 1, "RNA_property_as_string");
buf_esc = MEM_malloc_arrayN<char>(size_t(length) * 2 + 1, "RNA_property_as_string esc");
RNA_property_string_get(ptr, prop, buf);
BLI_str_escape(buf_esc, buf, length * 2 + 1);
MEM_freeN(buf);
ss << fmt::format("\"{}\"", buf_esc);
MEM_freeN(buf_esc);
break;
}
case PROP_ENUM: {
/* string arrays don't exist */
const char *identifier;
int val = RNA_property_enum_get(ptr, prop);
if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
/* represent as a python set */
if (val) {
const EnumPropertyItem *item_array;
bool free;
ss << "{";
RNA_property_enum_items(C, ptr, prop, &item_array, nullptr, &free);
if (item_array) {
const EnumPropertyItem *item = item_array;
bool is_first = true;
for (; item->identifier; item++) {
if (item->identifier[0] && item->value & val) {
ss << fmt::format(fmt::runtime(is_first ? "'{}'" : ", '{}'"), item->identifier);
is_first = false;
}
}
if (free) {
MEM_freeN(item_array);
}
}
ss << "}";
}
else {
/* annoying exception, don't confuse with dictionary syntax above: {} */
ss << "set()";
}
}
else if (RNA_property_enum_identifier(C, ptr, prop, val, &identifier)) {
ss << fmt::format("'{}'", identifier);
}
else {
return "'<UNKNOWN ENUM>'";
}
break;
}
case PROP_POINTER: {
PointerRNA tptr = RNA_property_pointer_get(ptr, prop);
ss << RNA_pointer_as_string(C, ptr, prop, &tptr).value_or("");
break;
}
case PROP_COLLECTION: {
int i = 0;
CollectionPropertyIterator collect_iter;
ss << "[";
for (RNA_property_collection_begin(ptr, prop, &collect_iter);
(i < max_prop_length) && collect_iter.valid;
RNA_property_collection_next(&collect_iter), i++)
{
PointerRNA itemptr = collect_iter.ptr;
if (i != 0) {
ss << ", ";
}
/* now get every prop of the collection */
ss << RNA_pointer_as_string(C, ptr, prop, &itemptr).value_or("");
}
RNA_property_collection_end(&collect_iter);
ss << "]";
break;
}
default:
return "'<UNKNOWN TYPE>'"; /* TODO */
}
return ss.str();
}
/* Function */
const char *RNA_function_identifier(FunctionRNA *func)
{
return func->identifier;
}
const char *RNA_function_ui_description(FunctionRNA *func)
{
return TIP_(func->description);
}
const char *RNA_function_ui_description_raw(FunctionRNA *func)
{
return func->description;
}
int RNA_function_flag(FunctionRNA *func)
{
return func->flag;
}
int RNA_function_defined(FunctionRNA *func)
{
return func->call != nullptr;
}
PropertyRNA *RNA_function_get_parameter(PointerRNA * /*ptr*/, FunctionRNA *func, int index)
{
return static_cast<PropertyRNA *>(BLI_findlink(&func->cont.properties, index));
}
PropertyRNA *RNA_function_find_parameter(PointerRNA * /*ptr*/,
FunctionRNA *func,
const char *identifier)
{
PropertyRNA *parm;
parm = static_cast<PropertyRNA *>(func->cont.properties.first);
for (; parm; parm = parm->next) {
if (STREQ(RNA_property_identifier(parm), identifier)) {
break;
}
}
return parm;
}
const ListBase *RNA_function_defined_parameters(FunctionRNA *func)
{
return &func->cont.properties;
}
/* Utility */
int RNA_parameter_flag(PropertyRNA *prop)
{
return int(rna_ensure_property(prop)->flag_parameter);
}
ParameterList *RNA_parameter_list_create(ParameterList *parms,
PointerRNA * /*ptr*/,
FunctionRNA *func)
{
PointerRNA null_ptr = PointerRNA_NULL;
void *data;
int alloc_size = 0, size;
parms->arg_count = 0;
parms->ret_count = 0;
/* allocate data */
LISTBASE_FOREACH (PropertyRNA *, parm, &func->cont.properties) {
alloc_size += rna_parameter_size_pad(rna_parameter_size(parm));
if (parm->flag_parameter & PARM_OUTPUT) {
parms->ret_count++;
}
else {
parms->arg_count++;
}
}
parms->data = MEM_callocN(alloc_size, "RNA_parameter_list_create");
parms->func = func;
parms->alloc_size = alloc_size;
/* set default values */
data = parms->data;
LISTBASE_FOREACH (PropertyRNA *, parm, &func->cont.properties) {
size = rna_parameter_size(parm);
/* set length to 0, these need to be set later, see bpy_array.c's py_to_array */
if (parm->flag & PROP_DYNAMIC) {
ParameterDynAlloc *data_alloc = static_cast<ParameterDynAlloc *>(data);
data_alloc->array_tot = 0;
data_alloc->array = nullptr;
}
else if ((parm->flag_parameter & PARM_RNAPTR) && (parm->flag & PROP_THICK_WRAP)) {
BLI_assert(parm->type == PROP_POINTER);
new (static_cast<PointerRNA *>(data)) PointerRNA();
}
if (!(parm->flag_parameter & PARM_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) {
switch (parm->type) {
case PROP_BOOLEAN:
if (parm->arraydimension) {
rna_property_boolean_get_default_array_values(
&null_ptr, (BoolPropertyRNA *)parm, static_cast<bool *>(data));
}
else {
memcpy(data, &((BoolPropertyRNA *)parm)->defaultvalue, size);
}
break;
case PROP_INT:
if (parm->arraydimension) {
rna_property_int_get_default_array_values(
&null_ptr, (IntPropertyRNA *)parm, static_cast<int *>(data));
}
else {
memcpy(data, &((IntPropertyRNA *)parm)->defaultvalue, size);
}
break;
case PROP_FLOAT:
if (parm->arraydimension) {
rna_property_float_get_default_array_values(
&null_ptr, (FloatPropertyRNA *)parm, static_cast<float *>(data));
}
else {
memcpy(data, &((FloatPropertyRNA *)parm)->defaultvalue, size);
}
break;
case PROP_ENUM:
memcpy(data, &((EnumPropertyRNA *)parm)->defaultvalue, size);
break;
case PROP_STRING: {
const char *defvalue = ((StringPropertyRNA *)parm)->defaultvalue;
if (defvalue && defvalue[0]) {
/* Causes bug #29988, possibly this is only correct for thick wrapped
* need to look further into it - campbell */
#if 0
BLI_strncpy(data, defvalue, size);
#else
memcpy(data, &defvalue, size);
#endif
}
break;
}
case PROP_POINTER:
case PROP_COLLECTION:
break;
}
}
data = ((char *)data) + rna_parameter_size_pad(size);
}
return parms;
}
void RNA_parameter_list_free(ParameterList *parms)
{
PropertyRNA *parm;
parm = static_cast<PropertyRNA *>(parms->func->cont.properties.first);
void *data = parms->data;
for (; parm; parm = parm->next) {
if (parm->type == PROP_COLLECTION) {
CollectionVector *vector = static_cast<CollectionVector *>(data);
vector->~CollectionVector();
}
else if ((parm->flag_parameter & PARM_RNAPTR) && (parm->flag & PROP_THICK_WRAP)) {
BLI_assert(parm->type == PROP_POINTER);
PointerRNA *ptr = static_cast<PointerRNA *>(data);
/* #RNA_parameter_list_create ensures that 'thick wrap' PointerRNA parameters are
* constructed. */
ptr->~PointerRNA();
}
else if (parm->flag & PROP_DYNAMIC) {
/* for dynamic arrays and strings, data is a pointer to an array */
ParameterDynAlloc *data_alloc = static_cast<ParameterDynAlloc *>(data);
if (data_alloc->array) {
MEM_freeN(data_alloc->array);
}
}
data = static_cast<char *>(data) + rna_parameter_size_pad(rna_parameter_size(parm));
}
MEM_freeN(parms->data);
parms->data = nullptr;
parms->func = nullptr;
}
int RNA_parameter_list_size(const ParameterList *parms)
{
return parms->alloc_size;
}
int RNA_parameter_list_arg_count(const ParameterList *parms)
{
return parms->arg_count;
}
int RNA_parameter_list_ret_count(const ParameterList *parms)
{
return parms->ret_count;
}
void RNA_parameter_list_begin(ParameterList *parms, ParameterIterator *iter)
{
/* may be useful but unused now */
// RNA_pointer_create_discrete(nullptr, &RNA_Function, parms->func, &iter->funcptr); /* UNUSED */
iter->parms = parms;
iter->parm = static_cast<PropertyRNA *>(parms->func->cont.properties.first);
iter->valid = iter->parm != nullptr;
iter->offset = 0;
if (iter->valid) {
iter->size = rna_parameter_size(iter->parm);
iter->data = ((char *)iter->parms->data); /* +iter->offset, always 0 */
}
}
void RNA_parameter_list_next(ParameterIterator *iter)
{
iter->offset += rna_parameter_size_pad(iter->size);
iter->parm = iter->parm->next;
iter->valid = iter->parm != nullptr;
if (iter->valid) {
iter->size = rna_parameter_size(iter->parm);
iter->data = (((char *)iter->parms->data) + iter->offset);
}
}
void RNA_parameter_list_end(ParameterIterator * /*iter*/)
{
/* nothing to do */
}
void RNA_parameter_get(ParameterList *parms, PropertyRNA *parm, void **r_value)
{
ParameterIterator iter;
RNA_parameter_list_begin(parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
if (iter.parm == parm) {
break;
}
}
if (iter.valid) {
if (parm->flag & PROP_DYNAMIC) {
/* for dynamic arrays and strings, data is a pointer to an array */
ParameterDynAlloc *data_alloc = static_cast<ParameterDynAlloc *>(iter.data);
*r_value = data_alloc->array;
}
else {
*r_value = iter.data;
}
}
else {
*r_value = nullptr;
}
RNA_parameter_list_end(&iter);
}
void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void **r_value)
{
PropertyRNA *parm;
parm = static_cast<PropertyRNA *>(parms->func->cont.properties.first);
for (; parm; parm = parm->next) {
if (STREQ(RNA_property_identifier(parm), identifier)) {
break;
}
}
if (parm) {
RNA_parameter_get(parms, parm, r_value);
}
}
void RNA_parameter_set(ParameterList *parms, PropertyRNA *parm, const void *value)
{
ParameterIterator iter;
RNA_parameter_list_begin(parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
if (iter.parm == parm) {
break;
}
}
if (iter.valid) {
if (parm->flag & PROP_DYNAMIC) {
/* for dynamic arrays and strings, data is a pointer to an array */
ParameterDynAlloc *data_alloc = static_cast<ParameterDynAlloc *>(iter.data);
size_t size = 0;
switch (parm->type) {
case PROP_STRING:
size = sizeof(char);
break;
case PROP_INT:
case PROP_BOOLEAN:
size = sizeof(int);
break;
case PROP_FLOAT:
size = sizeof(float);
break;
default:
break;
}
size *= data_alloc->array_tot;
if (data_alloc->array) {
MEM_freeN(data_alloc->array);
}
data_alloc->array = MEM_mallocN(size, __func__);
memcpy(data_alloc->array, value, size);
}
else if ((parm->flag_parameter & PARM_RNAPTR) && (parm->flag & PROP_THICK_WRAP)) {
BLI_assert(parm->type == PROP_POINTER);
BLI_assert(iter.size == sizeof(PointerRNA));
PointerRNA *ptr = static_cast<PointerRNA *>(iter.data);
/* #RNA_parameter_list_create ensures that 'thick wrap' PointerRNA parameters are
* constructed. */
*ptr = PointerRNA(*static_cast<const PointerRNA *>(value));
}
else {
memcpy(iter.data, value, iter.size);
}
}
RNA_parameter_list_end(&iter);
}
void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, const void *value)
{
PropertyRNA *parm;
parm = static_cast<PropertyRNA *>(parms->func->cont.properties.first);
for (; parm; parm = parm->next) {
if (STREQ(RNA_property_identifier(parm), identifier)) {
break;
}
}
if (parm) {
RNA_parameter_set(parms, parm, value);
}
}
int RNA_parameter_dynamic_length_get(ParameterList *parms, PropertyRNA *parm)
{
ParameterIterator iter;
int len = 0;
RNA_parameter_list_begin(parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
if (iter.parm == parm) {
break;
}
}
if (iter.valid) {
len = RNA_parameter_dynamic_length_get_data(parms, parm, iter.data);
}
RNA_parameter_list_end(&iter);
return len;
}
void RNA_parameter_dynamic_length_set(ParameterList *parms, PropertyRNA *parm, int length)
{
ParameterIterator iter;
RNA_parameter_list_begin(parms, &iter);
for (; iter.valid; RNA_parameter_list_next(&iter)) {
if (iter.parm == parm) {
break;
}
}
if (iter.valid) {
RNA_parameter_dynamic_length_set_data(parms, parm, iter.data, length);
}
RNA_parameter_list_end(&iter);
}
int RNA_parameter_dynamic_length_get_data(ParameterList * /*parms*/, PropertyRNA *parm, void *data)
{
if (parm->flag & PROP_DYNAMIC) {
return int(((ParameterDynAlloc *)data)->array_tot);
}
return 0;
}
void RNA_parameter_dynamic_length_set_data(ParameterList * /*parms*/,
PropertyRNA *parm,
void *data,
int length)
{
if (parm->flag & PROP_DYNAMIC) {
((ParameterDynAlloc *)data)->array_tot = intptr_t(length);
}
}
int RNA_function_call(
bContext *C, ReportList *reports, PointerRNA *ptr, FunctionRNA *func, ParameterList *parms)
{
if (func->call) {
func->call(C, reports, ptr, parms);
return 0;
}
return -1;
}
std::optional<blender::StringRefNull> RNA_translate_ui_text(
const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, int translate)
{
return rna_translate_ui_text(text, text_ctxt, type, prop, translate);
}
bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
{
int len;
/* get the length of the array to work with */
len = RNA_property_array_length(ptr, prop);
/* get and set the default values as appropriate for the various types */
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (len) {
if (index == -1) {
bool *tmparray = MEM_calloc_arrayN<bool>(len, __func__);
RNA_property_boolean_get_default_array(ptr, prop, tmparray);
RNA_property_boolean_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
int value = RNA_property_boolean_get_default_index(ptr, prop, index);
RNA_property_boolean_set_index(ptr, prop, index, value);
}
}
else {
int value = RNA_property_boolean_get_default(ptr, prop);
RNA_property_boolean_set(ptr, prop, value);
}
return true;
case PROP_INT:
if (len) {
if (index == -1) {
int *tmparray = MEM_calloc_arrayN<int>(len, __func__);
RNA_property_int_get_default_array(ptr, prop, tmparray);
RNA_property_int_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
int value = RNA_property_int_get_default_index(ptr, prop, index);
RNA_property_int_set_index(ptr, prop, index, value);
}
}
else {
int value = RNA_property_int_get_default(ptr, prop);
RNA_property_int_set(ptr, prop, value);
}
return true;
case PROP_FLOAT:
if (len) {
if (index == -1) {
float *tmparray = MEM_calloc_arrayN<float>(len, __func__);
RNA_property_float_get_default_array(ptr, prop, tmparray);
RNA_property_float_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
float value = RNA_property_float_get_default_index(ptr, prop, index);
RNA_property_float_set_index(ptr, prop, index, value);
}
}
else {
float value = RNA_property_float_get_default(ptr, prop);
RNA_property_float_set(ptr, prop, value);
}
return true;
case PROP_ENUM: {
int value = RNA_property_enum_get_default(ptr, prop);
RNA_property_enum_set(ptr, prop, value);
return true;
}
case PROP_STRING: {
char *value = RNA_property_string_get_default_alloc(ptr, prop, nullptr, 0, nullptr);
RNA_property_string_set(ptr, prop, value);
MEM_freeN(value);
return true;
}
case PROP_POINTER: {
PointerRNA value = RNA_property_pointer_get_default(ptr, prop);
RNA_property_pointer_set(ptr, prop, value, nullptr);
return true;
}
default:
/* FIXME: are there still any cases that haven't been handled?
* comment out "default" block to check :) */
return false;
}
}
bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
{
if (!RNA_property_is_idprop(prop) || RNA_property_array_check(prop)) {
return false;
}
/* get and set the default values as appropriate for the various types */
switch (RNA_property_type(prop)) {
case PROP_INT: {
int value = RNA_property_int_get(ptr, prop);
return RNA_property_int_set_default(prop, value);
}
case PROP_FLOAT: {
float value = RNA_property_float_get(ptr, prop);
return RNA_property_float_set_default(prop, value);
}
default:
return false;
}
}
#ifdef WITH_PYTHON
extern void PyC_LineSpit();
#endif
void _RNA_warning(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
/* gcc macro adds '\n', but can't use for other compilers */
#ifndef __GNUC__
fputc('\n', stdout);
#endif
#ifdef WITH_PYTHON
{
PyC_LineSpit();
}
#endif
}
bool RNA_path_resolved_create(PointerRNA *ptr,
PropertyRNA *prop,
const int prop_index,
PathResolvedRNA *r_anim_rna)
{
int array_len = RNA_property_array_length(ptr, prop);
if ((array_len == 0) || (prop_index < array_len)) {
r_anim_rna->ptr = *ptr;
r_anim_rna->prop = prop;
r_anim_rna->prop_index = array_len ? prop_index : -1;
return true;
}
return false;
}
static char rna_struct_state_owner[128];
void RNA_struct_state_owner_set(const char *name)
{
if (name) {
STRNCPY(rna_struct_state_owner, name);
}
else {
rna_struct_state_owner[0] = '\0';
}
}
const char *RNA_struct_state_owner_get()
{
if (rna_struct_state_owner[0]) {
return rna_struct_state_owner;
}
return nullptr;
}