Files
test/source/blender/makesrna/intern/rna_define.cc
2023-12-07 10:38:54 +11:00

4959 lines
139 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup RNA
*/
#include <cctype>
#include <cfloat>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
#include "DNA_genfile.h"
#include "DNA_sdna_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLT_translation.h"
#include "UI_interface.hh" /* For things like UI_PRECISION_FLOAT_MAX... */
#include "RNA_define.hh"
#include "rna_internal.h"
#include "CLG_log.h"
static CLG_LogRef LOG = {"rna.define"};
#ifndef NDEBUG
# define ASSERT_SOFT_HARD_LIMITS \
if (softmin < hardmin || softmax > hardmax) { \
CLOG_ERROR(&LOG, "error with soft/hard limits: %s.%s", CONTAINER_RNA_ID(cont), identifier); \
BLI_assert_msg(0, "invalid soft/hard limits"); \
} \
(void)0
#else
# define ASSERT_SOFT_HARD_LIMITS (void)0
#endif
/* Global used during defining */
BlenderDefRNA DefRNA = {
/*sdna*/ nullptr,
/*structs*/ {nullptr, nullptr},
/*allocs*/ {nullptr, nullptr},
/*laststruct*/ nullptr,
/*error*/ false,
/*silent*/ false,
/*preprocess*/ false,
/*verify*/ true,
/*animate*/ true,
/*make_overridable*/ false,
};
#ifndef RNA_RUNTIME
static struct {
GHash *struct_map_static_from_alias;
} g_version_data;
#endif
#ifndef RNA_RUNTIME
/**
* When set, report details about which defaults are used.
* Noisy but handy when investigating default extraction.
*/
static bool debugSRNA_defaults = false;
static void print_default_info(const PropertyDefRNA *dp)
{
fprintf(stderr,
"dna_type=%s, dna_offset=%d, dna_struct=%s, dna_name=%s, id=%s\n",
dp->dnatype,
dp->dnaoffset,
dp->dnastructname,
dp->dnaname,
dp->prop->identifier);
}
#endif /* !RNA_RUNTIME */
/* Duplicated code since we can't link in blenkernel or blenlib */
/* pedantic check for final '.', note '...' are allowed though. */
#ifndef NDEBUG
# define DESCR_CHECK(description, id1, id2) \
if (description && (description)[0]) { \
int i = strlen(description); \
if (i > 3 && (description)[i - 1] == '.' && (description)[i - 3] != '.') { \
CLOG_WARN(&LOG, \
"'%s' description from '%s' '%s' ends with a '.' !", \
description, \
id1 ? id1 : "", \
id2 ? id2 : ""); \
} \
} \
(void)0
#else
# define DESCR_CHECK(description, id1, id2)
#endif
void rna_addtail(ListBase *listbase, void *vlink)
{
Link *link = static_cast<Link *>(vlink);
link->next = nullptr;
link->prev = static_cast<Link *>(listbase->last);
if (listbase->last) {
((Link *)listbase->last)->next = link;
}
if (listbase->first == nullptr) {
listbase->first = link;
}
listbase->last = link;
}
static void rna_remlink(ListBase *listbase, void *vlink)
{
Link *link = static_cast<Link *>(vlink);
if (link->next) {
link->next->prev = link->prev;
}
if (link->prev) {
link->prev->next = link->next;
}
if (listbase->last == link) {
listbase->last = link->prev;
}
if (listbase->first == link) {
listbase->first = link->next;
}
}
PropertyDefRNA *rna_findlink(ListBase *listbase, const char *identifier)
{
LISTBASE_FOREACH (Link *, link, listbase) {
PropertyRNA *prop = ((PropertyDefRNA *)link)->prop;
if (prop && STREQ(prop->identifier, identifier)) {
return (PropertyDefRNA *)link;
}
}
return nullptr;
}
void rna_freelinkN(ListBase *listbase, void *vlink)
{
rna_remlink(listbase, vlink);
MEM_freeN(vlink);
}
void rna_freelistN(ListBase *listbase)
{
Link *link, *next;
for (link = static_cast<Link *>(listbase->first); link; link = next) {
next = link->next;
MEM_freeN(link);
}
listbase->first = listbase->last = nullptr;
}
static void rna_brna_structs_add(BlenderRNA *brna, StructRNA *srna)
{
rna_addtail(&brna->structs, srna);
brna->structs_len += 1;
/* This exception is only needed for pre-processing.
* otherwise we don't allow empty names. */
if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && (srna->identifier[0] != '\0')) {
BLI_ghash_insert(brna->structs_map, (void *)srna->identifier, srna);
}
}
#ifdef RNA_RUNTIME
static void rna_brna_structs_remove_and_free(BlenderRNA *brna, StructRNA *srna)
{
if ((srna->flag & STRUCT_PUBLIC_NAMESPACE) && brna->structs_map) {
if (srna->identifier[0] != '\0') {
BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, nullptr, nullptr);
}
}
RNA_def_struct_free_pointers(nullptr, srna);
if (srna->flag & STRUCT_RUNTIME) {
rna_freelinkN(&brna->structs, srna);
}
brna->structs_len -= 1;
}
#endif
static int DNA_struct_find_nr_wrapper(const SDNA *sdna, const char *struct_name)
{
struct_name = DNA_struct_rename_legacy_hack_static_from_alias(struct_name);
#ifdef RNA_RUNTIME
/* We may support this at some point but for now we don't. */
BLI_assert_unreachable();
#else
struct_name = static_cast<const char *>(BLI_ghash_lookup_default(
g_version_data.struct_map_static_from_alias, struct_name, (void *)struct_name));
#endif
return DNA_struct_find_without_alias(sdna, struct_name);
}
StructDefRNA *rna_find_struct_def(StructRNA *srna)
{
StructDefRNA *dsrna;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
dsrna = static_cast<StructDefRNA *>(DefRNA.structs.last);
for (; dsrna; dsrna = static_cast<StructDefRNA *>(dsrna->cont.prev)) {
if (dsrna->srna == srna) {
return dsrna;
}
}
return nullptr;
}
PropertyDefRNA *rna_find_struct_property_def(StructRNA *srna, PropertyRNA *prop)
{
StructDefRNA *dsrna;
PropertyDefRNA *dprop;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
dsrna = rna_find_struct_def(srna);
dprop = static_cast<PropertyDefRNA *>(dsrna->cont.properties.last);
for (; dprop; dprop = dprop->prev) {
if (dprop->prop == prop) {
return dprop;
}
}
dsrna = static_cast<StructDefRNA *>(DefRNA.structs.last);
for (; dsrna; dsrna = static_cast<StructDefRNA *>(dsrna->cont.prev)) {
dprop = static_cast<PropertyDefRNA *>(dsrna->cont.properties.last);
for (; dprop; dprop = dprop->prev) {
if (dprop->prop == prop) {
return dprop;
}
}
}
return nullptr;
}
#if 0
static PropertyDefRNA *rna_find_property_def(PropertyRNA *prop)
{
PropertyDefRNA *dprop;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
dprop = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dprop) {
return dprop;
}
dprop = rna_find_parameter_def(prop);
if (dprop) {
return dprop;
}
return nullptr;
}
#endif
FunctionDefRNA *rna_find_function_def(FunctionRNA *func)
{
StructDefRNA *dsrna;
FunctionDefRNA *dfunc;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
dsrna = rna_find_struct_def(DefRNA.laststruct);
dfunc = static_cast<FunctionDefRNA *>(dsrna->functions.last);
for (; dfunc; dfunc = static_cast<FunctionDefRNA *>(dfunc->cont.prev)) {
if (dfunc->func == func) {
return dfunc;
}
}
dsrna = static_cast<StructDefRNA *>(DefRNA.structs.last);
for (; dsrna; dsrna = static_cast<StructDefRNA *>(dsrna->cont.prev)) {
dfunc = static_cast<FunctionDefRNA *>(dsrna->functions.last);
for (; dfunc; dfunc = static_cast<FunctionDefRNA *>(dfunc->cont.prev)) {
if (dfunc->func == func) {
return dfunc;
}
}
}
return nullptr;
}
PropertyDefRNA *rna_find_parameter_def(PropertyRNA *parm)
{
StructDefRNA *dsrna;
FunctionDefRNA *dfunc;
PropertyDefRNA *dparm;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
dsrna = rna_find_struct_def(DefRNA.laststruct);
dfunc = static_cast<FunctionDefRNA *>(dsrna->functions.last);
for (; dfunc; dfunc = static_cast<FunctionDefRNA *>(dfunc->cont.prev)) {
dparm = static_cast<PropertyDefRNA *>(dfunc->cont.properties.last);
for (; dparm; dparm = dparm->prev) {
if (dparm->prop == parm) {
return dparm;
}
}
}
dsrna = static_cast<StructDefRNA *>(DefRNA.structs.last);
for (; dsrna; dsrna = static_cast<StructDefRNA *>(dsrna->cont.prev)) {
dfunc = static_cast<FunctionDefRNA *>(dsrna->functions.last);
for (; dfunc; dfunc = static_cast<FunctionDefRNA *>(dfunc->cont.prev)) {
dparm = static_cast<PropertyDefRNA *>(dfunc->cont.properties.last);
for (; dparm; dparm = dparm->prev) {
if (dparm->prop == parm) {
return dparm;
}
}
}
}
return nullptr;
}
static ContainerDefRNA *rna_find_container_def(ContainerRNA *cont)
{
StructDefRNA *ds;
FunctionDefRNA *dfunc;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return nullptr;
}
ds = rna_find_struct_def((StructRNA *)cont);
if (ds) {
return &ds->cont;
}
dfunc = rna_find_function_def((FunctionRNA *)cont);
if (dfunc) {
return &dfunc->cont;
}
return nullptr;
}
/* DNA utility function for looking up members */
struct DNAStructMember {
const char *type;
const char *name;
int arraylength;
int pointerlevel;
int offset;
int size;
};
static int rna_member_cmp(const char *name, const char *oname)
{
int a = 0;
/* compare without pointer or array part */
while (name[0] == '*') {
name++;
}
while (oname[0] == '*') {
oname++;
}
while (true) {
if (name[a] == '[' && oname[a] == 0) {
return 1;
}
if (name[a] == '[' && oname[a] == '[') {
return 1;
}
if (name[a] == 0) {
break;
}
if (name[a] != oname[a]) {
return 0;
}
a++;
}
if (name[a] == 0 && oname[a] == '.') {
return 2;
}
if (name[a] == 0 && oname[a] == '-' && oname[a + 1] == '>') {
return 3;
}
return (name[a] == oname[a]);
}
static int rna_find_sdna_member(SDNA *sdna,
const char *structname,
const char *membername,
DNAStructMember *smember,
int *offset)
{
const char *dnaname;
int b, structnr, cmp;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return 0;
}
structnr = DNA_struct_find_nr_wrapper(sdna, structname);
smember->offset = -1;
if (structnr == -1) {
if (offset) {
*offset = -1;
}
return 0;
}
const SDNA_Struct *struct_info = sdna->structs[structnr];
for (int a = 0; a < struct_info->members_len; a++) {
const SDNA_StructMember *member = &struct_info->members[a];
const int size = DNA_struct_member_size(sdna, member->type, member->name);
dnaname = sdna->alias.names[member->name];
cmp = rna_member_cmp(dnaname, membername);
if (cmp == 1) {
smember->type = sdna->alias.types[member->type];
smember->name = dnaname;
smember->offset = *offset;
smember->size = size;
if (strstr(membername, "[")) {
smember->arraylength = 0;
}
else {
smember->arraylength = DNA_elem_array_size(smember->name);
}
smember->pointerlevel = 0;
for (b = 0; dnaname[b] == '*'; b++) {
smember->pointerlevel++;
}
return 1;
}
if (cmp == 2) {
smember->type = "";
smember->name = dnaname;
smember->offset = *offset;
smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
membername = strstr(membername, ".") + strlen(".");
rna_find_sdna_member(sdna, sdna->alias.types[member->type], membername, smember, offset);
return 1;
}
if (cmp == 3) {
smember->type = "";
smember->name = dnaname;
smember->offset = *offset;
smember->size = size;
smember->pointerlevel = 0;
smember->arraylength = 0;
if (offset) {
*offset = -1;
}
membername = strstr(membername, "->") + strlen("->");
rna_find_sdna_member(sdna, sdna->alias.types[member->type], membername, smember, offset);
return 1;
}
if (offset && *offset != -1) {
*offset += size;
}
}
return 0;
}
static bool rna_validate_identifier(const char *identifier, bool property, const char **r_error)
{
int a = 0;
/**
* List is from:
* \code{.py}
* ", ".join([
* '"%s"' % kw for kw in __import__("keyword").kwlist
* if kw not in {"False", "None", "True"}
* ])
* \endcode
*/
static const char *kwlist[] = {
/* "False", "None", "True", */
"and", "as", "assert", "async", "await", "break", "class", "continue", "def",
"del", "elif", "else", "except", "finally", "for", "from", "global", "if",
"import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
"return", "try", "while", "with", "yield", nullptr,
};
if (!isalpha(identifier[0])) {
*r_error = "first character failed isalpha() check";
return false;
}
for (a = 0; identifier[a]; a++) {
if (DefRNA.preprocess && property) {
if (isalpha(identifier[a]) && isupper(identifier[a])) {
*r_error = "property names must contain lower case characters only";
return false;
}
}
if (identifier[a] == '_') {
continue;
}
if (identifier[a] == ' ') {
*r_error = "spaces are not okay in identifier names";
return false;
}
if (isalnum(identifier[a]) == 0) {
*r_error = "one of the characters failed an isalnum() check and is not an underscore";
return false;
}
}
for (a = 0; kwlist[a]; a++) {
if (STREQ(identifier, kwlist[a])) {
*r_error = "this keyword is reserved by Python";
return false;
}
}
if (property) {
static const char *kwlist_prop[] = {
/* not keywords but reserved all the same because py uses */
"keys",
"values",
"items",
"get",
nullptr,
};
for (a = 0; kwlist_prop[a]; a++) {
if (STREQ(identifier, kwlist_prop[a])) {
*r_error = "this keyword is reserved by Python";
return false;
}
}
}
return true;
}
void RNA_identifier_sanitize(char *identifier, int property)
{
int a = 0;
/* list from http://docs.python.org/py3k/reference/lexical_analysis.html#keywords */
static const char *kwlist[] = {
/* "False", "None", "True", */
"and", "as", "assert", "break", "class", "continue", "def", "del",
"elif", "else", "except", "finally", "for", "from", "global", "if",
"import", "in", "is", "lambda", "nonlocal", "not", "or", "pass",
"raise", "return", "try", "while", "with", "yield", nullptr,
};
if (!isalpha(identifier[0])) {
/* first character failed isalpha() check */
identifier[0] = '_';
}
for (a = 0; identifier[a]; a++) {
if (DefRNA.preprocess && property) {
if (isalpha(identifier[a]) && isupper(identifier[a])) {
/* property names must contain lower case characters only */
identifier[a] = tolower(identifier[a]);
}
}
if (identifier[a] == '_') {
continue;
}
if (identifier[a] == ' ') {
/* spaces are not okay in identifier names */
identifier[a] = '_';
}
if (isalnum(identifier[a]) == 0) {
/* one of the characters failed an isalnum() check and is not an underscore */
identifier[a] = '_';
}
}
for (a = 0; kwlist[a]; a++) {
if (STREQ(identifier, kwlist[a])) {
/* this keyword is reserved by python.
* just replace the last character by '_' to keep it readable.
*/
identifier[strlen(identifier) - 1] = '_';
break;
}
}
if (property) {
static const char *kwlist_prop[] = {
/* not keywords but reserved all the same because py uses */
"keys",
"values",
"items",
"get",
nullptr,
};
for (a = 0; kwlist_prop[a]; a++) {
if (STREQ(identifier, kwlist_prop[a])) {
/* this keyword is reserved by python.
* just replace the last character by '_' to keep it readable.
*/
identifier[strlen(identifier) - 1] = '_';
break;
}
}
}
}
static bool rna_range_from_int_type(const char *dnatype, int r_range[2])
{
/* Type `char` is unsigned too. */
if (STREQ(dnatype, "char") || STREQ(dnatype, "uchar")) {
r_range[0] = CHAR_MIN;
r_range[1] = CHAR_MAX;
return true;
}
if (STREQ(dnatype, "short")) {
r_range[0] = SHRT_MIN;
r_range[1] = SHRT_MAX;
return true;
}
if (STREQ(dnatype, "int")) {
r_range[0] = INT_MIN;
r_range[1] = INT_MAX;
return true;
}
if (STREQ(dnatype, "int8_t")) {
r_range[0] = INT8_MIN;
r_range[1] = INT8_MAX;
return true;
}
return false;
}
/* Blender Data Definition */
BlenderRNA *RNA_create()
{
BlenderRNA *brna;
brna = static_cast<BlenderRNA *>(MEM_callocN(sizeof(BlenderRNA), "BlenderRNA"));
const char *error_message = nullptr;
BLI_listbase_clear(&DefRNA.structs);
brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048);
DefRNA.error = false;
DefRNA.preprocess = true;
/* We need both alias and static (on-disk) DNA names. */
const bool do_alias = true;
DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, do_alias, &error_message);
if (DefRNA.sdna == nullptr) {
CLOG_ERROR(&LOG, "Failed to decode SDNA: %s.", error_message);
DefRNA.error = true;
}
#ifndef RNA_RUNTIME
DNA_alias_maps(
DNA_RENAME_STATIC_FROM_ALIAS, &g_version_data.struct_map_static_from_alias, nullptr);
#endif
return brna;
}
void RNA_define_free(BlenderRNA * /*brna*/)
{
StructDefRNA *ds;
FunctionDefRNA *dfunc;
LISTBASE_FOREACH (AllocDefRNA *, alloc, &DefRNA.allocs) {
MEM_freeN(alloc->mem);
}
rna_freelistN(&DefRNA.allocs);
for (ds = static_cast<StructDefRNA *>(DefRNA.structs.first); ds;
ds = static_cast<StructDefRNA *>(ds->cont.next))
{
for (dfunc = static_cast<FunctionDefRNA *>(ds->functions.first); dfunc;
dfunc = static_cast<FunctionDefRNA *>(dfunc->cont.next))
{
rna_freelistN(&dfunc->cont.properties);
}
rna_freelistN(&ds->cont.properties);
rna_freelistN(&ds->functions);
}
rna_freelistN(&DefRNA.structs);
if (DefRNA.sdna) {
DNA_sdna_free(DefRNA.sdna);
DefRNA.sdna = nullptr;
}
DefRNA.error = false;
}
void RNA_define_verify_sdna(bool verify)
{
DefRNA.verify = verify;
}
void RNA_define_lib_overridable(const bool make_overridable)
{
DefRNA.make_overridable = make_overridable;
}
#ifndef RNA_RUNTIME
void RNA_define_animate_sdna(bool animate)
{
DefRNA.animate = animate;
}
#endif
#ifndef RNA_RUNTIME
void RNA_define_fallback_property_update(int noteflag, const char *updatefunc)
{
DefRNA.fallback.property_update.noteflag = noteflag;
DefRNA.fallback.property_update.updatefunc = updatefunc;
}
#endif
void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *rna_ext)
{
#ifdef RNA_RUNTIME
rna_ext->free(rna_ext->data); /* Decrefs the PyObject that the `srna` owns. */
RNA_struct_blender_type_set(srna, nullptr); /* FIXME: this gets accessed again. */
/* nullptr the srna's value so RNA_struct_free won't complain of a leak */
RNA_struct_py_type_set(srna, nullptr);
#else
(void)srna;
(void)rna_ext;
#endif
}
void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
{
#ifdef RNA_RUNTIME
FunctionRNA *func, *nextfunc;
PropertyRNA *prop, *nextprop;
PropertyRNA *parm, *nextparm;
# if 0
if (srna->flag & STRUCT_RUNTIME) {
if (RNA_struct_py_type_get(srna)) {
fprintf(stderr, "%s '%s' freed while holding a Python reference.", srna->identifier);
}
}
# endif
for (prop = static_cast<PropertyRNA *>(srna->cont.properties.first); prop; prop = nextprop) {
nextprop = prop->next;
RNA_def_property_free_pointers(prop);
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
rna_freelinkN(&srna->cont.properties, prop);
}
}
for (func = static_cast<FunctionRNA *>(srna->functions.first); func; func = nextfunc) {
nextfunc = static_cast<FunctionRNA *>(func->cont.next);
for (parm = static_cast<PropertyRNA *>(func->cont.properties.first); parm; parm = nextparm) {
nextparm = parm->next;
RNA_def_property_free_pointers(parm);
if (parm->flag_internal & PROP_INTERN_RUNTIME) {
rna_freelinkN(&func->cont.properties, parm);
}
}
RNA_def_func_free_pointers(func);
if (func->flag & FUNC_RUNTIME) {
rna_freelinkN(&srna->functions, func);
}
}
rna_brna_structs_remove_and_free(brna, srna);
#else
UNUSED_VARS(brna, srna);
#endif
}
void RNA_free(BlenderRNA *brna)
{
StructRNA *srna, *nextsrna;
FunctionRNA *func;
BLI_ghash_free(brna->structs_map, nullptr, nullptr);
brna->structs_map = nullptr;
if (DefRNA.preprocess) {
RNA_define_free(brna);
for (srna = static_cast<StructRNA *>(brna->structs.first); srna;
srna = static_cast<StructRNA *>(srna->cont.next))
{
for (func = static_cast<FunctionRNA *>(srna->functions.first); func;
func = static_cast<FunctionRNA *>(func->cont.next))
{
rna_freelistN(&func->cont.properties);
}
rna_freelistN(&srna->cont.properties);
rna_freelistN(&srna->functions);
}
rna_freelistN(&brna->structs);
MEM_freeN(brna);
}
else {
for (srna = static_cast<StructRNA *>(brna->structs.first); srna; srna = nextsrna) {
nextsrna = static_cast<StructRNA *>(srna->cont.next);
RNA_struct_free(brna, srna);
}
}
#ifndef RNA_RUNTIME
BLI_ghash_free(g_version_data.struct_map_static_from_alias, nullptr, nullptr);
g_version_data.struct_map_static_from_alias = nullptr;
#endif
}
static size_t rna_property_type_sizeof(PropertyType type)
{
switch (type) {
case PROP_BOOLEAN:
return sizeof(BoolPropertyRNA);
case PROP_INT:
return sizeof(IntPropertyRNA);
case PROP_FLOAT:
return sizeof(FloatPropertyRNA);
case PROP_STRING:
return sizeof(StringPropertyRNA);
case PROP_ENUM:
return sizeof(EnumPropertyRNA);
case PROP_POINTER:
return sizeof(PointerPropertyRNA);
case PROP_COLLECTION:
return sizeof(CollectionPropertyRNA);
default:
return 0;
}
}
static StructDefRNA *rna_find_def_struct(StructRNA *srna)
{
StructDefRNA *ds;
for (ds = static_cast<StructDefRNA *>(DefRNA.structs.first); ds;
ds = static_cast<StructDefRNA *>(ds->cont.next))
{
if (ds->srna == srna) {
return ds;
}
}
return nullptr;
}
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom)
{
StructRNA *srna;
StructDefRNA *ds = nullptr, *dsfrom = nullptr;
PropertyRNA *prop;
if (DefRNA.preprocess) {
const char *error = nullptr;
if (!rna_validate_identifier(identifier, false, &error)) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error);
DefRNA.error = true;
}
}
srna = static_cast<StructRNA *>(MEM_callocN(sizeof(StructRNA), "StructRNA"));
DefRNA.laststruct = srna;
if (srnafrom) {
/* Copy from struct to derive stuff, a bit clumsy since we can't
* use #MEM_dupallocN, data structs may not be allocated but builtin. */
memcpy(srna, srnafrom, sizeof(StructRNA));
srna->cont.prophash = nullptr;
BLI_listbase_clear(&srna->cont.properties);
BLI_listbase_clear(&srna->functions);
srna->py_type = nullptr;
srna->base = srnafrom;
if (DefRNA.preprocess) {
dsfrom = rna_find_def_struct(srnafrom);
}
else {
if (srnafrom->flag & STRUCT_PUBLIC_NAMESPACE_INHERIT) {
RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT);
}
else {
RNA_def_struct_clear_flag(srna, STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT);
}
}
}
srna->identifier = identifier;
srna->name = identifier; /* may be overwritten later RNA_def_struct_ui_text */
srna->description = "";
/* may be overwritten later RNA_def_struct_translation_context */
srna->translation_context = BLT_I18NCONTEXT_DEFAULT_BPYRNA;
if (!srnafrom) {
srna->icon = ICON_DOT;
RNA_def_struct_flag(srna, STRUCT_UNDO);
}
if (DefRNA.preprocess) {
RNA_def_struct_flag(srna, STRUCT_PUBLIC_NAMESPACE);
}
rna_brna_structs_add(brna, srna);
if (DefRNA.preprocess) {
ds = static_cast<StructDefRNA *>(MEM_callocN(sizeof(StructDefRNA), "StructDefRNA"));
ds->srna = srna;
rna_addtail(&DefRNA.structs, ds);
if (dsfrom) {
ds->dnafromname = dsfrom->dnaname;
}
}
/* in preprocess, try to find sdna */
if (DefRNA.preprocess) {
RNA_def_struct_sdna(srna, srna->identifier);
}
else {
RNA_def_struct_flag(srna, STRUCT_RUNTIME);
}
if (srnafrom) {
srna->nameproperty = srnafrom->nameproperty;
srna->iteratorproperty = srnafrom->iteratorproperty;
}
else {
/* define some builtin properties */
prop = RNA_def_property(&srna->cont, "rna_properties", PROP_COLLECTION, PROP_NONE);
prop->flag_internal |= PROP_INTERN_BUILTIN;
RNA_def_property_ui_text(prop, "Properties", "RNA property collection");
if (DefRNA.preprocess) {
RNA_def_property_struct_type(prop, "Property");
RNA_def_property_collection_funcs(prop,
"rna_builtin_properties_begin",
"rna_builtin_properties_next",
"rna_iterator_listbase_end",
"rna_builtin_properties_get",
nullptr,
nullptr,
"rna_builtin_properties_lookup_string",
nullptr);
}
else {
#ifdef RNA_RUNTIME
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
cprop->begin = rna_builtin_properties_begin;
cprop->next = rna_builtin_properties_next;
cprop->get = rna_builtin_properties_get;
cprop->item_type = &RNA_Property;
#endif
}
prop = RNA_def_property(&srna->cont, "rna_type", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_property_ui_text(prop, "RNA", "RNA type definition");
if (DefRNA.preprocess) {
RNA_def_property_struct_type(prop, "Struct");
RNA_def_property_pointer_funcs(prop, "rna_builtin_type_get", nullptr, nullptr, nullptr);
}
else {
#ifdef RNA_RUNTIME
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
pprop->get = rna_builtin_type_get;
pprop->type = &RNA_Struct;
#endif
}
}
return srna;
}
StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *from)
{
StructRNA *srnafrom = nullptr;
/* only use RNA_def_struct() while pre-processing, otherwise use RNA_def_struct_ptr() */
BLI_assert(DefRNA.preprocess);
if (from) {
/* find struct to derive from */
/* Inline RNA_struct_find(...) because it won't link from here. */
srnafrom = static_cast<StructRNA *>(BLI_ghash_lookup(brna->structs_map, from));
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier);
DefRNA.error = true;
}
}
return RNA_def_struct_ptr(brna, identifier, srnafrom);
}
void RNA_def_struct_sdna(StructRNA *srna, const char *structname)
{
StructDefRNA *ds;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
ds = rna_find_def_struct(srna);
/* There are far too many structs which initialize without valid DNA struct names,
* this can't be checked without adding an option to disable
* (tested this and it means changes all over - Campbell) */
#if 0
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
DefRNA.error = true;
}
return;
}
#endif
ds->dnaname = structname;
}
void RNA_def_struct_sdna_from(StructRNA *srna, const char *structname, const char *propname)
{
StructDefRNA *ds;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
ds = rna_find_def_struct(srna);
if (!ds->dnaname) {
CLOG_ERROR(&LOG, "%s base struct must know DNA already.", structname);
return;
}
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
DefRNA.error = true;
}
return;
}
ds->dnafromprop = propname;
ds->dnaname = structname;
}
void RNA_def_struct_name_property(StructRNA *srna, PropertyRNA *prop)
{
if (prop->type != PROP_STRING) {
CLOG_ERROR(&LOG, "\"%s.%s\", must be a string property.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
else if (srna->nameproperty != nullptr) {
CLOG_ERROR(
&LOG, "\"%s.%s\", name property is already set.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
else {
srna->nameproperty = prop;
}
}
void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *structname)
{
StructRNA *srnafrom;
/* find struct to derive from */
srnafrom = static_cast<StructRNA *>(BLI_ghash_lookup(brna->structs_map, structname));
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found for %s.", structname, srna->identifier);
DefRNA.error = true;
}
srna->nested = srnafrom;
}
void RNA_def_struct_flag(StructRNA *srna, int flag)
{
srna->flag |= flag;
}
void RNA_def_struct_clear_flag(StructRNA *srna, int flag)
{
srna->flag &= ~flag;
}
void RNA_def_struct_property_tags(StructRNA *srna, const EnumPropertyItem *prop_tag_defines)
{
srna->prop_tag_defines = prop_tag_defines;
}
void RNA_def_struct_refine_func(StructRNA *srna, const char *refine)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (refine) {
srna->refine = (StructRefineFunc)refine;
}
}
void RNA_def_struct_idprops_func(StructRNA *srna, const char *idproperties)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (idproperties) {
srna->idproperties = (IDPropertiesFunc)idproperties;
}
}
void RNA_def_struct_register_funcs(StructRNA *srna,
const char *reg,
const char *unreg,
const char *instance)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (reg) {
srna->reg = (StructRegisterFunc)reg;
}
if (unreg) {
srna->unreg = (StructUnregisterFunc)unreg;
}
if (instance) {
srna->instance = (StructInstanceFunc)instance;
}
}
void RNA_def_struct_path_func(StructRNA *srna, const char *path)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (path) {
srna->path = (StructPathFunc)path;
}
}
void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return;
}
/* Operator registration may set twice, see: operator_properties_init */
if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
if (identifier != srna->identifier) {
if (srna->identifier[0] != '\0') {
BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, nullptr, nullptr);
}
if (identifier[0] != '\0') {
BLI_ghash_insert(brna->structs_map, (void *)identifier, srna);
}
}
}
srna->identifier = identifier;
}
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return;
}
srna->identifier = identifier;
}
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description)
{
DESCR_CHECK(description, srna->identifier, nullptr);
srna->name = name;
srna->description = description;
}
void RNA_def_struct_ui_icon(StructRNA *srna, int icon)
{
srna->icon = icon;
}
void RNA_def_struct_translation_context(StructRNA *srna, const char *context)
{
srna->translation_context = context ? context : BLT_I18NCONTEXT_DEFAULT_BPYRNA;
}
/* Property Definition */
PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
const char *identifier,
int type,
int subtype)
{
// StructRNA *srna = DefRNA.laststruct; /* Invalid for Python defined props. */
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
ContainerDefRNA *dcont;
PropertyDefRNA *dprop = nullptr;
PropertyRNA *prop;
if (DefRNA.preprocess) {
const char *error = nullptr;
if (!rna_validate_identifier(identifier, true, &error)) {
CLOG_ERROR(
&LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error);
DefRNA.error = true;
}
dcont = rna_find_container_def(cont);
/* TODO: detect super-type collisions. */
if (rna_findlink(&dcont->properties, identifier)) {
CLOG_ERROR(&LOG, "duplicate identifier \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier);
DefRNA.error = true;
}
dprop = static_cast<PropertyDefRNA *>(MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA"));
rna_addtail(&dcont->properties, dprop);
}
else {
#ifndef NDEBUG
const char *error = nullptr;
if (!rna_validate_identifier(identifier, true, &error)) {
CLOG_ERROR(&LOG,
"runtime property identifier \"%s.%s\" - %s",
CONTAINER_RNA_ID(cont),
identifier,
error);
DefRNA.error = true;
}
#endif
}
prop = static_cast<PropertyRNA *>(
MEM_callocN(rna_property_type_sizeof(PropertyType(type)), "PropertyRNA"));
switch (type) {
case PROP_BOOLEAN:
if (DefRNA.preprocess) {
if ((subtype & ~PROP_LAYER_MEMBER) != PROP_NONE) {
CLOG_ERROR(&LOG,
"subtype does not apply to 'PROP_BOOLEAN' \"%s.%s\"",
CONTAINER_RNA_ID(cont),
identifier);
DefRNA.error = true;
}
}
break;
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
#ifndef RNA_RUNTIME
if (subtype == PROP_DISTANCE) {
CLOG_ERROR(&LOG,
"subtype does not apply to 'PROP_INT' \"%s.%s\"",
CONTAINER_RNA_ID(cont),
identifier);
DefRNA.error = true;
}
#endif
iprop->hardmin = (subtype == PROP_UNSIGNED) ? 0 : INT_MIN;
iprop->hardmax = INT_MAX;
iprop->softmin = (subtype == PROP_UNSIGNED) ? 0 : -10000; /* rather arbitrary. */
iprop->softmax = 10000;
iprop->step = 1;
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->hardmin = (subtype == PROP_UNSIGNED) ? 0.0f : -FLT_MAX;
fprop->hardmax = FLT_MAX;
if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA)) {
fprop->softmin = fprop->hardmin = 0.0f;
fprop->softmax = 1.0f;
}
else if (subtype == PROP_FACTOR) {
fprop->softmin = fprop->hardmin = 0.0f;
fprop->softmax = fprop->hardmax = 1.0f;
}
else {
fprop->softmin = (subtype == PROP_UNSIGNED) ? 0.0f : -10000.0f; /* rather arbitrary. */
fprop->softmax = 10000.0f;
}
fprop->step = 10;
fprop->precision = 3;
break;
}
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
/* By default don't allow nullptr string args, callers may clear.
* Used so generated 'get/length/set' functions skip a nullptr check
* in some cases we want it */
RNA_def_property_flag(prop, PROP_NEVER_NULL);
sprop->defaultvalue = "";
break;
}
case PROP_POINTER:
/* needed for default behavior when PARM_RNAPTR is set */
RNA_def_property_flag(prop, PROP_THICK_WRAP);
break;
case PROP_ENUM:
case PROP_COLLECTION:
break;
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid property type.", CONTAINER_RNA_ID(cont), identifier);
DefRNA.error = true;
return nullptr;
}
if (DefRNA.preprocess) {
dprop->cont = cont;
dprop->prop = prop;
}
prop->magic = RNA_MAGIC;
prop->identifier = identifier;
prop->type = PropertyType(type);
prop->subtype = PropertySubType(subtype);
prop->name = identifier;
prop->description = "";
prop->translation_context = BLT_I18NCONTEXT_DEFAULT_BPYRNA;
/* a priori not raw editable */
prop->rawtype = RawPropertyType(-1);
if (!ELEM(type, PROP_COLLECTION, PROP_POINTER)) {
RNA_def_property_flag(prop, PROP_EDITABLE);
if (type != PROP_STRING) {
#ifdef RNA_RUNTIME
RNA_def_property_flag(prop, PROP_ANIMATABLE);
#else
if (DefRNA.animate) {
RNA_def_property_flag(prop, PROP_ANIMATABLE);
}
#endif
}
}
#ifndef RNA_RUNTIME
if (DefRNA.make_overridable) {
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
}
#endif
if (DefRNA.preprocess) {
switch (type) {
case PROP_BOOLEAN:
DefRNA.silent = true;
RNA_def_property_boolean_sdna(prop, nullptr, identifier, 0);
DefRNA.silent = false;
break;
case PROP_INT: {
DefRNA.silent = true;
RNA_def_property_int_sdna(prop, nullptr, identifier);
DefRNA.silent = false;
break;
}
case PROP_FLOAT: {
DefRNA.silent = true;
RNA_def_property_float_sdna(prop, nullptr, identifier);
DefRNA.silent = false;
break;
}
case PROP_STRING: {
DefRNA.silent = true;
RNA_def_property_string_sdna(prop, nullptr, identifier);
DefRNA.silent = false;
break;
}
case PROP_ENUM:
DefRNA.silent = true;
RNA_def_property_enum_sdna(prop, nullptr, identifier);
DefRNA.silent = false;
break;
case PROP_POINTER:
DefRNA.silent = true;
RNA_def_property_pointer_sdna(prop, nullptr, identifier);
DefRNA.silent = false;
break;
case PROP_COLLECTION:
DefRNA.silent = true;
RNA_def_property_collection_sdna(prop, nullptr, identifier, nullptr);
DefRNA.silent = false;
break;
}
}
else {
RNA_def_property_flag(prop, PROP_IDPROPERTY);
prop->flag_internal |= PROP_INTERN_RUNTIME;
#ifdef RNA_RUNTIME
if (cont->prophash) {
BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop);
}
#endif
}
/* Override handling. */
if (DefRNA.preprocess) {
prop->override_diff = (RNAPropOverrideDiff)(void *)"rna_property_override_diff_default";
prop->override_store = (RNAPropOverrideStore)(void *)"rna_property_override_store_default";
prop->override_apply = (RNAPropOverrideApply)(void *)"rna_property_override_apply_default";
}
/* TODO: do we want that for runtime-defined stuff too? Id say no, but... maybe yes :/ */
#ifndef RNA_RUNTIME
/* Both are typically cleared. */
RNA_def_property_update(
prop, DefRNA.fallback.property_update.noteflag, DefRNA.fallback.property_update.updatefunc);
#endif
rna_addtail(&cont->properties, prop);
return prop;
}
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag |= flag;
}
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag &= ~flag;
if (flag & PROP_PTR_NO_OWNERSHIP) {
prop->flag_internal |= PROP_INTERN_PTR_OWNERSHIP_FORCED;
}
}
void RNA_def_property_override_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
{
prop->flag_override |= flag;
}
void RNA_def_property_override_clear_flag(PropertyRNA *prop, PropertyOverrideFlag flag)
{
prop->flag_override &= ~flag;
}
void RNA_def_property_tags(PropertyRNA *prop, int tags)
{
prop->tags |= tags;
}
void RNA_def_parameter_flags(PropertyRNA *prop,
PropertyFlag flag_property,
ParameterFlag flag_parameter)
{
prop->flag |= flag_property;
prop->flag_parameter |= flag_parameter;
}
void RNA_def_parameter_clear_flags(PropertyRNA *prop,
PropertyFlag flag_property,
ParameterFlag flag_parameter)
{
prop->flag &= ~flag_property;
prop->flag_parameter &= ~flag_parameter;
}
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
{
prop->subtype = subtype;
}
void RNA_def_property_array(PropertyRNA *prop, int length)
{
StructRNA *srna = DefRNA.laststruct;
if (length < 0) {
CLOG_ERROR(&LOG,
"\"%s.%s\", array length must be zero of greater.",
srna->identifier,
prop->identifier);
DefRNA.error = true;
return;
}
if (length > RNA_MAX_ARRAY_LENGTH) {
CLOG_ERROR(&LOG,
"\"%s.%s\", array length must be smaller than %d.",
srna->identifier,
prop->identifier,
RNA_MAX_ARRAY_LENGTH);
DefRNA.error = true;
return;
}
if (prop->arraydimension > 1) {
CLOG_ERROR(&LOG,
"\"%s.%s\", array dimensions has been set to %u but would be overwritten as 1.",
srna->identifier,
prop->identifier,
prop->arraydimension);
DefRNA.error = true;
return;
}
switch (prop->type) {
case PROP_BOOLEAN:
case PROP_INT:
case PROP_FLOAT:
prop->arraylength[0] = length;
prop->totarraylength = length;
prop->arraydimension = 1;
break;
default:
CLOG_ERROR(&LOG,
"\"%s.%s\", only boolean/int/float can be array.",
srna->identifier,
prop->identifier);
DefRNA.error = true;
break;
}
}
const float rna_default_quaternion[4] = {1, 0, 0, 0};
const float rna_default_axis_angle[4] = {0, 0, 1, 0};
const float rna_default_scale_3d[3] = {1, 1, 1};
const int rna_matrix_dimsize_3x3[] = {3, 3};
const int rna_matrix_dimsize_4x4[] = {4, 4};
const int rna_matrix_dimsize_4x2[] = {4, 2};
void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int length[])
{
StructRNA *srna = DefRNA.laststruct;
int i;
if (dimension < 1 || dimension > RNA_MAX_ARRAY_DIMENSION) {
CLOG_ERROR(&LOG,
"\"%s.%s\", array dimension must be between 1 and %d.",
srna->identifier,
prop->identifier,
RNA_MAX_ARRAY_DIMENSION);
DefRNA.error = true;
return;
}
switch (prop->type) {
case PROP_BOOLEAN:
case PROP_INT:
case PROP_FLOAT:
break;
default:
CLOG_ERROR(&LOG,
"\"%s.%s\", only boolean/int/float can be array.",
srna->identifier,
prop->identifier);
DefRNA.error = true;
break;
}
prop->arraydimension = dimension;
prop->totarraylength = 0;
if (length) {
memcpy(prop->arraylength, length, sizeof(int) * dimension);
prop->totarraylength = length[0];
for (i = 1; i < dimension; i++) {
prop->totarraylength *= length[i];
}
}
else {
memset(prop->arraylength, 0, sizeof(prop->arraylength));
}
/* TODO: make sure `arraylength` values are sane. */
}
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
{
DESCR_CHECK(description, prop->identifier, nullptr);
prop->name = name;
prop->description = description;
}
void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
{
prop->icon = icon;
if (consecutive != 0) {
RNA_def_property_flag(prop, PROP_ICONS_CONSECUTIVE);
}
if (consecutive < 0) {
RNA_def_property_flag(prop, PROP_ICONS_REVERSE);
}
}
void RNA_def_property_ui_range(
PropertyRNA *prop, double min, double max, double step, int precision)
{
StructRNA *srna = DefRNA.laststruct;
#ifndef NDEBUG
if (min > max) {
CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
if (step < 0 || step > 100) {
CLOG_ERROR(&LOG, "\"%s.%s\", step outside range.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
if (step == 0) {
CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
#endif
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
iprop->softmin = int(min);
iprop->softmax = int(max);
iprop->step = int(step);
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->softmin = float(min);
fprop->softmax = float(max);
fprop->step = float(step);
fprop->precision = int(precision);
break;
}
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for ui range.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_ui_scale_type(PropertyRNA *prop, PropertyScaleType ui_scale_type)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
iprop->ui_scale_type = ui_scale_type;
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->ui_scale_type = ui_scale_type;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid type for scale.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_range(PropertyRNA *prop, double min, double max)
{
StructRNA *srna = DefRNA.laststruct;
#ifndef NDEBUG
if (min > max) {
CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
#endif
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
iprop->hardmin = int(min);
iprop->hardmax = int(max);
iprop->softmin = std::max(int(min), iprop->hardmin);
iprop->softmax = std::min(int(max), iprop->hardmax);
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->hardmin = float(min);
fprop->hardmax = float(max);
fprop->softmin = std::max(float(min), fprop->hardmin);
fprop->softmax = std::min(float(max), fprop->hardmax);
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid type for range.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_struct_type(PropertyRNA *prop, const char *type)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
fprintf(stderr, "\"%s.%s\": only during preprocessing.", srna->identifier, prop->identifier);
return;
}
switch (prop->type) {
case PROP_POINTER: {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
pprop->type = (StructRNA *)type;
break;
}
case PROP_COLLECTION: {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
cprop->item_type = (StructRNA *)type;
break;
}
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_struct_runtime(StructOrFunctionRNA *cont, PropertyRNA *prop, StructRNA *type)
{
/* Never valid when defined from python. */
StructRNA *srna = DefRNA.laststruct;
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return;
}
const bool is_id_type = (type->flag & STRUCT_ID) != 0;
switch (prop->type) {
case PROP_POINTER: {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
pprop->type = type;
/* Check between `cont` and `srna` is mandatory, since when defined from python
* `DefRNA.laststruct` is not valid.
* This is not an issue as bpy code already checks for this case on its own. */
if (cont == srna && (srna->flag & STRUCT_NO_DATABLOCK_IDPROPERTIES) != 0 && is_id_type) {
CLOG_ERROR(&LOG,
"\"%s.%s\", this struct type (probably an Operator, Keymap or UserPreference) "
"does not accept ID pointer properties.",
CONTAINER_RNA_ID(cont),
prop->identifier);
DefRNA.error = true;
return;
}
if (type && (type->flag & STRUCT_ID_REFCOUNT)) {
RNA_def_property_flag(prop, PROP_ID_REFCOUNT);
}
break;
}
case PROP_COLLECTION: {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
cprop->item_type = type;
break;
}
default:
CLOG_ERROR(&LOG,
"\"%s.%s\", invalid type for struct type.",
CONTAINER_RNA_ID(cont),
prop->identifier);
DefRNA.error = true;
return;
}
if (is_id_type) {
RNA_def_property_flag(prop, PROP_PTR_NO_OWNERSHIP);
}
}
void RNA_def_property_enum_native_type(PropertyRNA *prop, const char *native_enum_type)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
eprop->native_enum_type = native_enum_type;
break;
}
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
{
StructRNA *srna = DefRNA.laststruct;
int i, defaultfound = 0;
switch (prop->type) {
case PROP_ENUM: {
/* Access DNA size & range (for additional sanity checks). */
int enum_dna_size = -1;
int enum_dna_range[2];
if (DefRNA.preprocess) {
/* If this is larger, this is likely a string which can sometimes store enums. */
if (PropertyDefRNA *dp = rna_find_struct_property_def(srna, prop)) {
if (dp->dnatype == nullptr || dp->dnatype[0] == '\0') {
/* Unfortunately this happens when #PropertyDefRNA::dnastructname is for e.g.
* `type->region_type` there isn't a convenient way to access the int size. */
}
else if (dp->dnaarraylength > 1) {
/* When an array this is likely a string using get/set functions for enum access. */
}
else if (dp->dnasize == 0) {
/* Some cases function callbacks are used, the DNA size isn't known. */
}
else {
enum_dna_size = dp->dnasize;
if (!rna_range_from_int_type(dp->dnatype, enum_dna_range)) {
CLOG_ERROR(&LOG,
"\"%s.%s\", enum type \"%s\" size is not known.",
srna->identifier,
prop->identifier,
dp->dnatype);
}
}
}
}
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
eprop->item = (EnumPropertyItem *)item;
eprop->totitem = 0;
for (i = 0; item[i].identifier; i++) {
eprop->totitem++;
if (item[i].identifier[0]) {
/* Don't allow spaces in internal enum items (it's fine for Python ones). */
if (DefRNA.preprocess && strstr(item[i].identifier, " ")) {
CLOG_ERROR(&LOG,
"\"%s.%s\", enum identifiers must not contain spaces.",
srna->identifier,
prop->identifier);
DefRNA.error = true;
break;
}
/* When the integer size is known, check the flag wont fit. */
if (enum_dna_size != -1) {
if (prop->flag & PROP_ENUM_FLAG) {
uint32_t enum_type_mask = 0;
if (enum_dna_size == 1) {
enum_type_mask = 0xff;
}
else if (enum_dna_size == 2) {
enum_type_mask = 0xffff;
}
if (enum_type_mask != 0) {
if (uint32_t(item[i].value) != (uint32_t(item[i].value) & enum_type_mask)) {
CLOG_ERROR(&LOG,
"\"%s.%s\", enum value for '%s' does not fit into %d byte(s).",
srna->identifier,
prop->identifier,
item[i].identifier,
enum_dna_size);
DefRNA.error = true;
break;
}
}
}
else {
if (ELEM(enum_dna_size, 1, 2)) {
if ((item[i].value < enum_dna_range[0]) || (item[i].value > enum_dna_range[1])) {
CLOG_ERROR(&LOG,
"\"%s.%s\", enum value for '%s' is outside of range [%d - %d].",
srna->identifier,
prop->identifier,
item[i].identifier,
enum_dna_range[0],
enum_dna_range[1]);
DefRNA.error = true;
break;
}
}
}
}
if (item[i].value == eprop->defaultvalue) {
defaultfound = 1;
}
}
}
if (!defaultfound) {
for (i = 0; item[i].identifier; i++) {
if (item[i].identifier[0]) {
eprop->defaultvalue = item[i].value;
break;
}
}
}
break;
}
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_string_maxlength(PropertyRNA *prop, int maxlength)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
sprop->maxlength = maxlength;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_boolean_default(PropertyRNA *prop, bool value)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
BLI_assert(ELEM(value, false, true));
#ifndef RNA_RUNTIME
/* Default may be set from items. */
if (bprop->defaultvalue) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
bprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
bprop->defaultarray = array;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_int_default(PropertyRNA *prop, int value)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
#ifndef RNA_RUNTIME
if (iprop->defaultvalue != 0) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
iprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
#ifndef RNA_RUNTIME
if (iprop->defaultarray != nullptr) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
iprop->defaultarray = array;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_float_default(PropertyRNA *prop, float value)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
#ifndef RNA_RUNTIME
if (fprop->defaultvalue != 0) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
fprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
#ifndef RNA_RUNTIME
if (fprop->defaultarray != nullptr) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
fprop->defaultarray = array; /* WARNING, this array must not come from the stack and lost */
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
{
StructRNA *srna = DefRNA.laststruct;
switch (prop->type) {
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (value == nullptr) {
CLOG_ERROR(&LOG,
"\"%s.%s\", nullptr string passed (don't call in this case).",
srna->identifier,
prop->identifier);
DefRNA.error = true;
break;
}
if (!value[0]) {
CLOG_ERROR(&LOG,
"\"%s.%s\", empty string passed (don't call in this case).",
srna->identifier,
prop->identifier);
DefRNA.error = true;
// BLI_assert(0);
break;
}
#ifndef RNA_RUNTIME
if (sprop->defaultvalue != nullptr && sprop->defaultvalue[0]) {
CLOG_ERROR(&LOG, "\"%s.%s\", set from DNA.", srna->identifier, prop->identifier);
}
#endif
sprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
{
StructRNA *srna = DefRNA.laststruct;
int i, defaultfound = 0;
switch (prop->type) {
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
eprop->defaultvalue = value;
if (prop->flag & PROP_ENUM_FLAG) {
/* check all bits are accounted for */
int totflag = 0;
for (i = 0; i < eprop->totitem; i++) {
if (eprop->item[i].identifier[0]) {
totflag |= eprop->item[i].value;
}
}
if (eprop->defaultvalue & ~totflag) {
CLOG_ERROR(&LOG,
"\"%s.%s\", default includes unused bits (%d).",
srna->identifier,
prop->identifier,
eprop->defaultvalue & ~totflag);
DefRNA.error = true;
}
}
else {
for (i = 0; i < eprop->totitem; i++) {
if (eprop->item[i].identifier[0] && eprop->item[i].value == eprop->defaultvalue) {
defaultfound = 1;
}
}
if (!defaultfound && eprop->totitem) {
if (value == 0) {
eprop->defaultvalue = eprop->item[0].value;
}
else {
CLOG_ERROR(
&LOG, "\"%s.%s\", default is not in items.", srna->identifier, prop->identifier);
DefRNA.error = true;
}
}
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
/* SDNA */
static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
const char *structname,
const char *propname)
{
DNAStructMember smember;
StructDefRNA *ds;
PropertyDefRNA *dp;
dp = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dp == nullptr) {
return nullptr;
}
ds = rna_find_struct_def((StructRNA *)dp->cont);
if (!structname) {
structname = ds->dnaname;
}
if (!propname) {
propname = prop->identifier;
}
int dnaoffset = 0;
if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember, &dnaoffset)) {
if (DefRNA.silent) {
return nullptr;
}
if (!DefRNA.verify) {
/* some basic values to survive even with sdna info */
dp->dnastructname = structname;
dp->dnaname = propname;
if (prop->type == PROP_BOOLEAN) {
dp->dnaarraylength = 1;
}
if (prop->type == PROP_POINTER) {
dp->dnapointerlevel = 1;
}
dp->dnaoffset = smember.offset;
return dp;
}
CLOG_ERROR(&LOG,
"\"%s.%s\" (identifier \"%s\") not found. Struct must be in DNA.",
structname,
propname,
prop->identifier);
DefRNA.error = true;
return nullptr;
}
if (smember.arraylength > 1) {
prop->arraylength[0] = smember.arraylength;
prop->totarraylength = smember.arraylength;
prop->arraydimension = 1;
}
else {
prop->arraydimension = 0;
prop->totarraylength = 0;
}
dp->dnastructname = structname;
dp->dnastructfromname = ds->dnafromname;
dp->dnastructfromprop = ds->dnafromprop;
dp->dnaname = propname;
dp->dnatype = smember.type;
dp->dnaarraylength = smember.arraylength;
dp->dnapointerlevel = smember.pointerlevel;
dp->dnaoffset = smember.offset;
dp->dnasize = smember.size;
return dp;
}
void RNA_def_property_boolean_sdna(PropertyRNA *prop,
const char *structname,
const char *propname,
int64_t bit)
{
PropertyDefRNA *dp;
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_BOOLEAN) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (!DefRNA.silent) {
/* error check to ensure floats are not wrapped as ints/bools */
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_BOOLEAN_COMPAT(dp->dnatype) == 0) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
DefRNA.error = true;
return;
}
}
dp->booleanbit = bit;
#ifndef RNA_RUNTIME
/* Set the default if possible. */
if (dp->dnaoffset != -1) {
int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
if (SDNAnr != -1) {
const void *default_data = DNA_default_table[SDNAnr];
if (default_data) {
default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
bool has_default = true;
if (prop->totarraylength > 0) {
has_default = false;
if (debugSRNA_defaults) {
fprintf(stderr, "%s default: unsupported boolean array default\n", __func__);
}
}
else {
if (STREQ(dp->dnatype, "char")) {
bprop->defaultvalue = *(const char *)default_data & bit;
}
else if (STREQ(dp->dnatype, "short")) {
bprop->defaultvalue = *(const short *)default_data & bit;
}
else if (STREQ(dp->dnatype, "int")) {
bprop->defaultvalue = *(const int *)default_data & bit;
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(
stderr, "%s default: unsupported boolean type (%s)\n", __func__, dp->dnatype);
}
}
if (has_default) {
if (dp->booleannegative) {
bprop->defaultvalue = !bprop->defaultvalue;
}
if (debugSRNA_defaults) {
fprintf(stderr, "value=%d, ", bprop->defaultvalue);
print_default_info(dp);
}
}
}
}
}
}
#else
UNUSED_VARS(bprop);
#endif
}
}
void RNA_def_property_boolean_negative_sdna(PropertyRNA *prop,
const char *structname,
const char *propname,
int64_t booleanbit)
{
PropertyDefRNA *dp;
RNA_def_property_boolean_sdna(prop, structname, propname, booleanbit);
dp = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dp) {
dp->booleannegative = true;
}
}
void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
PropertyDefRNA *dp;
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_INT) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* error check to ensure floats are not wrapped as ints/bools */
if (!DefRNA.silent) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_INT_COMPAT(dp->dnatype) == 0) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
DefRNA.error = true;
return;
}
}
/* SDNA doesn't pass us unsigned unfortunately. */
if (dp->dnatype != nullptr && (dp->dnatype[0] != '\0')) {
int range[2];
if (rna_range_from_int_type(dp->dnatype, range)) {
iprop->hardmin = iprop->softmin = range[0];
iprop->hardmax = iprop->softmax = range[1];
}
else {
CLOG_ERROR(&LOG,
"\"%s.%s\", type \"%s\" range not known.",
srna->identifier,
prop->identifier,
dp->dnatype);
DefRNA.error = true;
}
/* Rather arbitrary that this is only done for one type. */
if (STREQ(dp->dnatype, "int")) {
iprop->softmin = -10000;
iprop->softmax = 10000;
}
}
if (ELEM(prop->subtype, PROP_UNSIGNED, PROP_PERCENTAGE, PROP_FACTOR)) {
iprop->hardmin = iprop->softmin = 0;
}
#ifndef RNA_RUNTIME
/* Set the default if possible. */
if (dp->dnaoffset != -1) {
int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
if (SDNAnr != -1) {
const void *default_data = DNA_default_table[SDNAnr];
if (default_data) {
default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
/* NOTE: Currently doesn't store sign, assume chars are unsigned because
* we build with this enabled, otherwise check 'PROP_UNSIGNED'. */
bool has_default = true;
if (prop->totarraylength > 0) {
const void *default_data_end = POINTER_OFFSET(default_data, dp->dnasize);
const int size_final = sizeof(int) * prop->totarraylength;
if (STREQ(dp->dnatype, "char")) {
int *defaultarray = static_cast<int *>(rna_calloc(size_final));
for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
defaultarray[i] = *(const char *)default_data;
default_data = POINTER_OFFSET(default_data, sizeof(char));
}
iprop->defaultarray = defaultarray;
}
else if (STREQ(dp->dnatype, "short")) {
int *defaultarray = static_cast<int *>(rna_calloc(size_final));
for (int i = 0; i < prop->totarraylength && default_data < default_data_end; i++) {
defaultarray[i] = (prop->subtype != PROP_UNSIGNED) ? *(const short *)default_data :
*(const ushort *)default_data;
default_data = POINTER_OFFSET(default_data, sizeof(short));
}
iprop->defaultarray = defaultarray;
}
else if (STREQ(dp->dnatype, "int")) {
int *defaultarray = static_cast<int *>(rna_calloc(size_final));
memcpy(defaultarray, default_data, std::min(size_final, dp->dnasize));
iprop->defaultarray = defaultarray;
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(stderr,
"%s default: unsupported int array type (%s)\n",
__func__,
dp->dnatype);
}
}
if (has_default) {
if (debugSRNA_defaults) {
fprintf(stderr, "value=(");
for (int i = 0; i < prop->totarraylength; i++) {
fprintf(stderr, "%d, ", iprop->defaultarray[i]);
}
fprintf(stderr, "), ");
print_default_info(dp);
}
}
}
else {
if (STREQ(dp->dnatype, "char")) {
iprop->defaultvalue = *(const char *)default_data;
}
else if (STREQ(dp->dnatype, "short")) {
iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ?
*(const short *)default_data :
*(const ushort *)default_data;
}
else if (STREQ(dp->dnatype, "int")) {
iprop->defaultvalue = (prop->subtype != PROP_UNSIGNED) ? *(const int *)default_data :
*(const uint *)default_data;
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(stderr, "%s default: unsupported int type (%s)\n", __func__, dp->dnatype);
}
}
if (has_default) {
if (debugSRNA_defaults) {
fprintf(stderr, "value=%d, ", iprop->defaultvalue);
print_default_info(dp);
}
}
}
}
}
}
#endif
}
}
void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
PropertyDefRNA *dp;
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_FLOAT) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* silent is for internal use */
if (!DefRNA.silent) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
/* Colors are an exception. these get translated. */
if (prop->subtype != PROP_COLOR_GAMMA) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
srna->identifier,
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
DefRNA.error = true;
return;
}
}
}
if (dp->dnatype && STREQ(dp->dnatype, "char")) {
fprop->hardmin = fprop->softmin = 0.0f;
fprop->hardmax = fprop->softmax = 1.0f;
}
#ifndef RNA_RUNTIME
/* Set the default if possible. */
if (dp->dnaoffset != -1) {
int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
if (SDNAnr != -1) {
const void *default_data = DNA_default_table[SDNAnr];
if (default_data) {
default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
bool has_default = true;
if (prop->totarraylength > 0) {
if (STREQ(dp->dnatype, "float")) {
const int size_final = sizeof(float) * prop->totarraylength;
float *defaultarray = static_cast<float *>(rna_calloc(size_final));
memcpy(defaultarray, default_data, std::min(size_final, dp->dnasize));
fprop->defaultarray = defaultarray;
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(stderr,
"%s default: unsupported float array type (%s)\n",
__func__,
dp->dnatype);
}
}
if (has_default) {
if (debugSRNA_defaults) {
fprintf(stderr, "value=(");
for (int i = 0; i < prop->totarraylength; i++) {
fprintf(stderr, "%g, ", fprop->defaultarray[i]);
}
fprintf(stderr, "), ");
print_default_info(dp);
}
}
}
else {
if (STREQ(dp->dnatype, "float")) {
fprop->defaultvalue = *(const float *)default_data;
}
else if (STREQ(dp->dnatype, "char")) {
fprop->defaultvalue = float(*(const char *)default_data) * (1.0f / 255.0f);
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(
stderr, "%s default: unsupported float type (%s)\n", __func__, dp->dnatype);
}
}
if (has_default) {
if (debugSRNA_defaults) {
fprintf(stderr, "value=%g, ", fprop->defaultvalue);
print_default_info(dp);
}
}
}
}
}
}
#endif
}
rna_def_property_sdna(prop, structname, propname);
}
void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
PropertyDefRNA *dp;
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_ENUM) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
prop->arraydimension = 0;
prop->totarraylength = 0;
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for enum type.", structname, propname);
DefRNA.error = true;
}
}
#ifndef RNA_RUNTIME
/* Set the default if possible. */
if (dp->dnaoffset != -1) {
int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
if (SDNAnr != -1) {
const void *default_data = DNA_default_table[SDNAnr];
if (default_data) {
default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
bool has_default = true;
if (STREQ(dp->dnatype, "char")) {
eprop->defaultvalue = *(const char *)default_data;
}
else if (STREQ(dp->dnatype, "short")) {
eprop->defaultvalue = *(const short *)default_data;
}
else if (STREQ(dp->dnatype, "int")) {
eprop->defaultvalue = *(const int *)default_data;
}
else {
has_default = false;
if (debugSRNA_defaults) {
fprintf(stderr, "%s default: unsupported enum type (%s)\n", __func__, dp->dnatype);
}
}
if (has_default) {
if (debugSRNA_defaults) {
fprintf(stderr, "value=%d, ", eprop->defaultvalue);
print_default_info(dp);
}
}
}
}
}
#else
UNUSED_VARS(eprop);
#endif
}
}
void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop,
const char *structname,
const char *propname)
{
PropertyDefRNA *dp;
RNA_def_property_enum_sdna(prop, structname, propname);
dp = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dp) {
dp->enumbitflags = 1;
#ifndef RNA_RUNTIME
int defaultvalue_mask = 0;
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
for (int i = 0; i < eprop->totitem; i++) {
if (eprop->item[i].identifier[0]) {
defaultvalue_mask |= eprop->defaultvalue & eprop->item[i].value;
}
}
eprop->defaultvalue = defaultvalue_mask;
#endif
}
}
void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
PropertyDefRNA *dp;
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_STRING) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
sprop->maxlength = prop->totarraylength;
prop->arraydimension = 0;
prop->totarraylength = 0;
}
#ifndef RNA_RUNTIME
/* Set the default if possible. */
if ((dp->dnaoffset != -1) && (dp->dnapointerlevel != 0)) {
int SDNAnr = DNA_struct_find_nr_wrapper(DefRNA.sdna, dp->dnastructname);
if (SDNAnr != -1) {
const void *default_data = DNA_default_table[SDNAnr];
if (default_data) {
default_data = POINTER_OFFSET(default_data, dp->dnaoffset);
sprop->defaultvalue = static_cast<const char *>(default_data);
if (debugSRNA_defaults) {
fprintf(stderr, "value=\"%s\", ", sprop->defaultvalue);
print_default_info(dp);
}
}
}
}
#endif
}
}
void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, const char *propname)
{
// PropertyDefRNA *dp;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_POINTER) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if (/* dp= */ rna_def_property_sdna(prop, structname, propname)) {
if (prop->arraydimension) {
prop->arraydimension = 0;
prop->totarraylength = 0;
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for pointer type.", structname, propname);
DefRNA.error = true;
}
}
}
}
void RNA_def_property_collection_sdna(PropertyRNA *prop,
const char *structname,
const char *propname,
const char *lengthpropname)
{
PropertyDefRNA *dp;
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (prop->type != PROP_COLLECTION) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier);
DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension && !lengthpropname) {
prop->arraydimension = 0;
prop->totarraylength = 0;
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array of collections not supported.", structname, propname);
DefRNA.error = true;
}
}
if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
cprop->next = (PropCollectionNextFunc)(void *)"rna_iterator_listbase_next";
cprop->get = (PropCollectionGetFunc)(void *)"rna_iterator_listbase_get";
cprop->end = (PropCollectionEndFunc)(void *)"rna_iterator_listbase_end";
}
}
if (dp && lengthpropname) {
DNAStructMember smember;
StructDefRNA *ds = rna_find_struct_def((StructRNA *)dp->cont);
if (!structname) {
structname = ds->dnaname;
}
int dnaoffset = 0;
if (lengthpropname[0] == 0 ||
rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember, &dnaoffset))
{
if (lengthpropname[0] == 0) {
dp->dnalengthfixed = prop->totarraylength;
prop->arraydimension = 0;
prop->totarraylength = 0;
}
else {
dp->dnalengthstructname = structname;
dp->dnalengthname = lengthpropname;
prop->totarraylength = 0;
}
cprop->next = (PropCollectionNextFunc)(void *)"rna_iterator_array_next";
cprop->end = (PropCollectionEndFunc)(void *)"rna_iterator_array_end";
if (dp->dnapointerlevel >= 2) {
cprop->get = (PropCollectionGetFunc)(void *)"rna_iterator_array_dereference_get";
}
else {
cprop->get = (PropCollectionGetFunc)(void *)"rna_iterator_array_get";
}
}
else {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\" not found.", structname, lengthpropname);
DefRNA.error = true;
}
}
}
}
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
{
prop->translation_context = context ? context : BLT_I18NCONTEXT_DEFAULT_BPYRNA;
}
/* Functions */
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (editable) {
prop->editable = (EditableFunc)editable;
}
}
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (editable) {
prop->itemeditable = (ItemEditableFunc)editable;
}
}
void RNA_def_property_override_funcs(PropertyRNA *prop,
const char *diff,
const char *store,
const char *apply)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (diff) {
prop->override_diff = (RNAPropOverrideDiff)diff;
}
if (store) {
prop->override_store = (RNAPropOverrideStore)store;
}
if (apply) {
prop->override_apply = (RNAPropOverrideApply)apply;
}
}
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
prop->noteflag = noteflag;
prop->update = (UpdateFunc)func;
}
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
{
prop->update = (UpdateFunc)func;
}
void RNA_def_property_update_runtime_with_context_and_property(
PropertyRNA *prop, RNAPropertyUpdateFuncWithContextAndProperty func)
{
prop->update = (UpdateFunc)func;
RNA_def_property_flag(prop, PROP_CONTEXT_PROPERTY_UPDATE);
}
void RNA_def_property_update_notifier(PropertyRNA *prop, const int noteflag)
{
prop->noteflag = noteflag;
}
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
{
if (prop->type == PROP_POINTER) {
((PointerPropertyRNA *)prop)->poll = (PropPointerPollFunc)func;
}
else {
CLOG_ERROR(&LOG, "%s is not a Pointer Property.", prop->identifier);
}
}
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength)
{
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
if (!(prop->flag & PROP_DYNAMIC)) {
CLOG_ERROR(&LOG, "property is a not dynamic array.");
DefRNA.error = true;
return;
}
if (getlength) {
prop->getlength = (PropArrayLengthGetFunc)getlength;
}
}
void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (prop->arraydimension) {
if (get) {
bprop->getarray = (PropBooleanArrayGetFunc)get;
}
if (set) {
bprop->setarray = (PropBooleanArraySetFunc)set;
}
}
else {
if (get) {
bprop->get = (PropBooleanGetFunc)get;
}
if (set) {
bprop->set = (PropBooleanSetFunc)set;
}
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_boolean_funcs_runtime(PropertyRNA *prop,
BooleanPropertyGetFunc getfunc,
BooleanPropertySetFunc setfunc)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (getfunc) {
bprop->get_ex = getfunc;
}
if (setfunc) {
bprop->set_ex = setfunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_boolean_array_funcs_runtime(PropertyRNA *prop,
BooleanArrayPropertyGetFunc getfunc,
BooleanArrayPropertySetFunc setfunc)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (getfunc) {
bprop->getarray_ex = getfunc;
}
if (setfunc) {
bprop->setarray_ex = setfunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_int_funcs(PropertyRNA *prop,
const char *get,
const char *set,
const char *range)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (prop->arraydimension) {
if (get) {
iprop->getarray = (PropIntArrayGetFunc)get;
}
if (set) {
iprop->setarray = (PropIntArraySetFunc)set;
}
}
else {
if (get) {
iprop->get = (PropIntGetFunc)get;
}
if (set) {
iprop->set = (PropIntSetFunc)set;
}
}
if (range) {
iprop->range = (PropIntRangeFunc)range;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_int_funcs_runtime(PropertyRNA *prop,
IntPropertyGetFunc getfunc,
IntPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (getfunc) {
iprop->get_ex = getfunc;
}
if (setfunc) {
iprop->set_ex = setfunc;
}
if (rangefunc) {
iprop->range_ex = rangefunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_int_array_funcs_runtime(PropertyRNA *prop,
IntArrayPropertyGetFunc getfunc,
IntArrayPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (getfunc) {
iprop->getarray_ex = getfunc;
}
if (setfunc) {
iprop->setarray_ex = setfunc;
}
if (rangefunc) {
iprop->range_ex = rangefunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_float_funcs(PropertyRNA *prop,
const char *get,
const char *set,
const char *range)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (prop->arraydimension) {
if (get) {
fprop->getarray = (PropFloatArrayGetFunc)get;
}
if (set) {
fprop->setarray = (PropFloatArraySetFunc)set;
}
}
else {
if (get) {
fprop->get = (PropFloatGetFunc)get;
}
if (set) {
fprop->set = (PropFloatSetFunc)set;
}
}
if (range) {
fprop->range = (PropFloatRangeFunc)range;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_float_funcs_runtime(PropertyRNA *prop,
FloatPropertyGetFunc getfunc,
FloatPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (getfunc) {
fprop->get_ex = getfunc;
}
if (setfunc) {
fprop->set_ex = setfunc;
}
if (rangefunc) {
fprop->range_ex = rangefunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_float_array_funcs_runtime(PropertyRNA *prop,
FloatArrayPropertyGetFunc getfunc,
FloatArrayPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (getfunc) {
fprop->getarray_ex = getfunc;
}
if (setfunc) {
fprop->setarray_ex = setfunc;
}
if (rangefunc) {
fprop->range_ex = rangefunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_enum_funcs(PropertyRNA *prop,
const char *get,
const char *set,
const char *item)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (get) {
eprop->get = (PropEnumGetFunc)get;
}
if (set) {
eprop->set = (PropEnumSetFunc)set;
}
if (item) {
eprop->item_fn = (PropEnumItemFunc)item;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
EnumPropertyGetFunc getfunc,
EnumPropertySetFunc setfunc,
EnumPropertyItemFunc itemfunc)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (getfunc) {
eprop->get_ex = getfunc;
}
if (setfunc) {
eprop->set_ex = setfunc;
}
if (itemfunc) {
eprop->item_fn = itemfunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_string_funcs(PropertyRNA *prop,
const char *get,
const char *length,
const char *set)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (get) {
sprop->get = (PropStringGetFunc)get;
}
if (length) {
sprop->length = (PropStringLengthFunc)length;
}
if (set) {
sprop->set = (PropStringSetFunc)set;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_string_search_func(PropertyRNA *prop,
const char *search,
const eStringPropertySearchFlag search_flag)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
sprop->search = (StringPropertySearchFunc)search;
if (search != nullptr) {
sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (getfunc) {
sprop->get_ex = getfunc;
}
if (lengthfunc) {
sprop->length_ex = lengthfunc;
}
if (setfunc) {
sprop->set_ex = setfunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
RNA_def_property_clear_flag(prop, PROP_IDPROPERTY);
if (!setfunc) {
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
}
void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
StringPropertySearchFunc search_fn,
const eStringPropertySearchFlag search_flag)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
sprop->search = search_fn;
if (search_fn != nullptr) {
sprop->search_flag = search_flag | PROP_STRING_SEARCH_SUPPORTED;
}
}
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_POINTER: {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
if (get) {
pprop->get = (PropPointerGetFunc)get;
}
if (set) {
pprop->set = (PropPointerSetFunc)set;
}
if (type_fn) {
pprop->type_fn = (PropPointerTypeFunc)type_fn;
}
if (poll) {
pprop->poll = (PropPointerPollFunc)poll;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_collection_funcs(PropertyRNA *prop,
const char *begin,
const char *next,
const char *end,
const char *get,
const char *length,
const char *lookupint,
const char *lookupstring,
const char *assignint)
{
StructRNA *srna = DefRNA.laststruct;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
switch (prop->type) {
case PROP_COLLECTION: {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)prop;
if (begin) {
cprop->begin = (PropCollectionBeginFunc)begin;
}
if (next) {
cprop->next = (PropCollectionNextFunc)next;
}
if (end) {
cprop->end = (PropCollectionEndFunc)end;
}
if (get) {
cprop->get = (PropCollectionGetFunc)get;
}
if (length) {
cprop->length = (PropCollectionLengthFunc)length;
}
if (lookupint) {
cprop->lookupint = (PropCollectionLookupIntFunc)lookupint;
}
if (lookupstring) {
cprop->lookupstring = (PropCollectionLookupStringFunc)lookupstring;
}
if (assignint) {
cprop->assignint = (PropCollectionAssignIntFunc)assignint;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier);
DefRNA.error = true;
break;
}
}
void RNA_def_property_srna(PropertyRNA *prop, const char *type)
{
const char *error = nullptr;
if (!rna_validate_identifier(type, false, &error)) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", type, error);
DefRNA.error = true;
return;
}
prop->srna = (StructRNA *)type;
}
void RNA_def_py_data(PropertyRNA *prop, void *py_data)
{
prop->py_data = py_data;
}
/* Compact definitions */
PropertyRNA *RNA_def_boolean(StructOrFunctionRNA *cont_,
const char *identifier,
bool default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_default(prop, default_value);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_layer(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_LAYER);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_layer_member(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_LAYER_MEMBER);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_XYZ); /* XXX */
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_int(StructOrFunctionRNA *cont_,
const char *identifier,
int default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_int_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const int *default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_XYZ); /* XXX */
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_int_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_int_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const int *default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_int_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_string(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
BLI_assert(default_value == nullptr || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_NONE);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_file_path(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
BLI_assert(default_value == nullptr || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_FILEPATH);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_dir_path(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
BLI_assert(default_value == nullptr || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_DIRPATH);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_file_name(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
BLI_assert(default_value == nullptr || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_FILENAME);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
int default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
if (items == nullptr) {
CLOG_ERROR(&LOG, "items not allowed to be nullptr.");
return nullptr;
}
prop = RNA_def_property(cont, identifier, PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, items);
RNA_def_property_enum_default(prop, default_value);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
int default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
if (items == nullptr) {
CLOG_ERROR(&LOG, "items not allowed to be nullptr.");
return nullptr;
}
prop = RNA_def_property(cont, identifier, PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_FLAG); /* important to run before default set */
RNA_def_property_enum_items(prop, items);
RNA_def_property_enum_default(prop, default_value);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
eprop->item_fn = itemfunc;
}
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_NONE);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_XYZ);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
PropertyRNA *prop;
prop = RNA_def_float_vector(cont_,
identifier,
len,
default_value,
hardmin,
hardmax,
ui_name,
ui_description,
softmin,
softmax);
prop->subtype = PROP_XYZ_LENGTH;
return prop;
}
PropertyRNA *RNA_def_float_color(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_COLOR);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont_,
const char *identifier,
int rows,
int columns,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
const int length[2] = {rows, columns};
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_MATRIX);
RNA_def_property_multi_array(prop, 2, length);
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_translation(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
PropertyRNA *prop;
prop = RNA_def_float_vector(cont_,
identifier,
len,
default_value,
hardmin,
hardmax,
ui_name,
ui_description,
softmin,
softmax);
prop->subtype = PROP_TRANSLATION;
RNA_def_property_ui_range(prop, softmin, softmax, 1, RNA_TRANSLATION_PREC_DEFAULT);
return prop;
}
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, (len >= 3) ? PROP_EULER : PROP_ANGLE);
if (len != 0) {
RNA_def_property_array(prop, len);
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
}
else {
/* RNA_def_property_float_default must be called outside */
BLI_assert(default_value == nullptr);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 10, 3);
return prop;
}
PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
PropertyRNA *prop = RNA_def_float(cont_,
identifier,
default_value,
hardmin,
hardmax,
ui_name,
ui_description,
softmin,
softmax);
RNA_def_property_subtype(prop, PROP_DISTANCE);
return prop;
}
PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
#ifndef NDEBUG
/* Properties with PROP_PERCENTAGE should use a range like 0 to 100, unlike PROP_FACTOR. */
if (hardmax < 2.0f) {
CLOG_WARN(&LOG,
"Percentage property with incorrect range: %s.%s",
CONTAINER_RNA_ID(cont),
identifier);
}
#endif
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont_,
const char *identifier,
const char *type,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, type);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_,
const char *identifier,
StructRNA *type,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_runtime(cont, prop, type);
if ((type->flag & STRUCT_ID) != 0) {
RNA_def_property_flag(prop, PROP_EDITABLE);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_collection(StructOrFunctionRNA *cont_,
const char *identifier,
const char *type,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, type);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_collection_runtime(StructOrFunctionRNA *cont_,
const char *identifier,
StructRNA *type,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_runtime(cont, prop, type);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
/* Function */
static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier)
{
FunctionRNA *func;
StructDefRNA *dsrna;
FunctionDefRNA *dfunc;
if (DefRNA.preprocess) {
const char *error = nullptr;
if (!rna_validate_identifier(identifier, false, &error)) {
CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error);
DefRNA.error = true;
}
}
func = static_cast<FunctionRNA *>(MEM_callocN(sizeof(FunctionRNA), "FunctionRNA"));
func->identifier = identifier;
func->description = identifier;
rna_addtail(&srna->functions, func);
if (DefRNA.preprocess) {
dsrna = rna_find_struct_def(srna);
dfunc = static_cast<FunctionDefRNA *>(MEM_callocN(sizeof(FunctionDefRNA), "FunctionDefRNA"));
rna_addtail(&dsrna->functions, dfunc);
dfunc->func = func;
}
else {
RNA_def_function_flag(func, FUNC_RUNTIME);
}
return func;
}
FunctionRNA *RNA_def_function(StructRNA *srna, const char *identifier, const char *call)
{
FunctionRNA *func;
FunctionDefRNA *dfunc;
if (BLI_findstring_ptr(&srna->functions, identifier, offsetof(FunctionRNA, identifier))) {
CLOG_ERROR(&LOG, "%s.%s already defined.", srna->identifier, identifier);
return nullptr;
}
func = rna_def_function(srna, identifier);
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at preprocess time.");
return func;
}
dfunc = rna_find_function_def(func);
dfunc->call = call;
return func;
}
FunctionRNA *RNA_def_function_runtime(StructRNA *srna, const char *identifier, CallFunc call)
{
FunctionRNA *func;
func = rna_def_function(srna, identifier);
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return func;
}
func->call = call;
return func;
}
void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret)
{
if (ret->flag & PROP_DYNAMIC) {
CLOG_ERROR(&LOG,
"\"%s.%s\", dynamic values are not allowed as strict returns, "
"use RNA_def_function_output instead.",
func->identifier,
ret->identifier);
return;
}
if (ret->arraydimension) {
CLOG_ERROR(&LOG,
"\"%s.%s\", arrays are not allowed as strict returns, "
"use RNA_def_function_output instead.",
func->identifier,
ret->identifier);
return;
}
BLI_assert(func->c_ret == nullptr);
func->c_ret = ret;
RNA_def_function_output(func, ret);
}
void RNA_def_function_output(FunctionRNA * /*func*/, PropertyRNA *ret)
{
ret->flag_parameter |= PARM_OUTPUT;
}
void RNA_def_function_flag(FunctionRNA *func, int flag)
{
func->flag |= flag;
}
void RNA_def_function_ui_description(FunctionRNA *func, const char *description)
{
func->description = description;
}
int rna_parameter_size(PropertyRNA *parm)
{
PropertyType ptype = parm->type;
int len = parm->totarraylength;
/* XXX in other parts is mentioned that strings can be dynamic as well */
if (parm->flag & PROP_DYNAMIC) {
return sizeof(ParameterDynAlloc);
}
if (len > 0) {
switch (ptype) {
case PROP_BOOLEAN:
return sizeof(bool) * len;
case PROP_INT:
return sizeof(int) * len;
case PROP_FLOAT:
return sizeof(float) * len;
default:
break;
}
}
else {
switch (ptype) {
case PROP_BOOLEAN:
return sizeof(bool);
case PROP_INT:
case PROP_ENUM:
return sizeof(int);
case PROP_FLOAT:
return sizeof(float);
case PROP_STRING:
/* return values don't store a pointer to the original */
if (parm->flag & PROP_THICK_WRAP) {
StringPropertyRNA *sparm = (StringPropertyRNA *)parm;
return sizeof(char) * sparm->maxlength;
}
else {
return sizeof(char *);
}
case PROP_POINTER: {
#ifdef RNA_RUNTIME
if (parm->flag_parameter & PARM_RNAPTR) {
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
else {
return sizeof(PointerRNA *);
}
}
else {
return sizeof(void *);
}
#else
if (parm->flag_parameter & PARM_RNAPTR) {
if (parm->flag & PROP_THICK_WRAP) {
return sizeof(PointerRNA);
}
return sizeof(PointerRNA *);
}
return sizeof(void *);
#endif
}
case PROP_COLLECTION:
return sizeof(ListBase);
}
}
return sizeof(void *);
}
int rna_parameter_size_pad(const int size)
{
/* Pad parameters in memory so the next parameter is properly aligned.
* This silences warnings in UBSAN. More complicated logic to pack parameters
* more tightly in memory is unlikely to improve performance, and aligning
* to the requirements for pointers is enough for all data types we use. */
const int alignment = sizeof(void *);
return (size + alignment - 1) & ~(alignment - 1);
}
/* Dynamic Enums */
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
{
int tot = *totitem;
if (tot == 0) {
*items = static_cast<EnumPropertyItem *>(MEM_callocN(sizeof(EnumPropertyItem[8]), __func__));
/* Ensure we get crashes on missing calls to 'RNA_enum_item_end', see #74227. */
#ifndef NDEBUG
memset(*items, 0xff, sizeof(EnumPropertyItem[8]));
#endif
}
else if (tot >= 8 && (tot & (tot - 1)) == 0) {
/* Power of two > 8. */
*items = static_cast<EnumPropertyItem *>(
MEM_recallocN_id(*items, sizeof(EnumPropertyItem) * tot * 2, __func__));
#ifndef NDEBUG
memset((*items) + tot, 0xff, sizeof(EnumPropertyItem) * tot);
#endif
}
(*items)[tot] = *item;
*totitem = tot + 1;
}
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
{
static const EnumPropertyItem sepr = RNA_ENUM_ITEM_SEPR;
RNA_enum_item_add(items, totitem, &sepr);
}
void RNA_enum_items_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
{
for (; item->identifier; item++) {
RNA_enum_item_add(items, totitem, item);
}
}
void RNA_enum_items_add_value(EnumPropertyItem **items,
int *totitem,
const EnumPropertyItem *item,
int value)
{
for (; item->identifier; item++) {
if (item->value == value) {
RNA_enum_item_add(items, totitem, item);
/* Break on first match - does this break anything?
* (is quick hack to get `object->parent_type` working ok for armature/lattice). */
break;
}
}
}
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
{
static const EnumPropertyItem empty = {0, nullptr, 0, nullptr, nullptr};
RNA_enum_item_add(items, totitem, &empty);
}
/* Memory management */
#ifdef RNA_RUNTIME
void RNA_def_struct_duplicate_pointers(BlenderRNA *brna, StructRNA *srna)
{
if (srna->identifier) {
srna->identifier = BLI_strdup(srna->identifier);
if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
BLI_ghash_replace_key(brna->structs_map, (void *)srna->identifier);
}
}
if (srna->name) {
srna->name = BLI_strdup(srna->name);
}
if (srna->description) {
srna->description = BLI_strdup(srna->description);
}
RNA_def_struct_flag(srna, STRUCT_FREE_POINTERS);
}
void RNA_def_struct_free_pointers(BlenderRNA *brna, StructRNA *srna)
{
if (srna->flag & STRUCT_FREE_POINTERS) {
if (srna->identifier) {
if (srna->flag & STRUCT_PUBLIC_NAMESPACE) {
if (brna != nullptr) {
BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, nullptr, nullptr);
}
}
MEM_freeN((void *)srna->identifier);
}
if (srna->name) {
MEM_freeN((void *)srna->name);
}
if (srna->description) {
MEM_freeN((void *)srna->description);
}
}
}
void RNA_def_func_duplicate_pointers(FunctionRNA *func)
{
if (func->identifier) {
func->identifier = BLI_strdup(func->identifier);
}
if (func->description) {
func->description = BLI_strdup(func->description);
}
RNA_def_function_flag(func, FUNC_FREE_POINTERS);
}
void RNA_def_func_free_pointers(FunctionRNA *func)
{
if (func->flag & FUNC_FREE_POINTERS) {
if (func->identifier) {
MEM_freeN((void *)func->identifier);
}
if (func->description) {
MEM_freeN((void *)func->description);
}
}
}
void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA *prop)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
int a;
/* annoying since we just added this to a hash, could make this add the correct key to the hash
* in the first place */
if (prop->identifier) {
if (cont->prophash) {
prop->identifier = BLI_strdup(prop->identifier);
BLI_ghash_reinsert(cont->prophash, (void *)prop->identifier, prop, nullptr, nullptr);
}
else {
prop->identifier = BLI_strdup(prop->identifier);
}
}
if (prop->name) {
prop->name = BLI_strdup(prop->name);
}
if (prop->description) {
prop->description = BLI_strdup(prop->description);
}
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (bprop->defaultarray) {
bool *array = static_cast<bool *>(
MEM_mallocN(sizeof(bool) * prop->totarraylength, "RNA_def_property_store"));
memcpy(array, bprop->defaultarray, sizeof(bool) * prop->totarraylength);
bprop->defaultarray = array;
}
break;
}
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (iprop->defaultarray) {
int *array = static_cast<int *>(
MEM_mallocN(sizeof(int) * prop->totarraylength, "RNA_def_property_store"));
memcpy(array, iprop->defaultarray, sizeof(int) * prop->totarraylength);
iprop->defaultarray = array;
}
break;
}
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (eprop->item) {
EnumPropertyItem *array = static_cast<EnumPropertyItem *>(MEM_mallocN(
sizeof(EnumPropertyItem) * (eprop->totitem + 1), "RNA_def_property_store"));
memcpy(array, eprop->item, sizeof(EnumPropertyItem) * (eprop->totitem + 1));
eprop->item = array;
for (a = 0; a < eprop->totitem; a++) {
if (array[a].identifier) {
array[a].identifier = BLI_strdup(array[a].identifier);
}
if (array[a].name) {
array[a].name = BLI_strdup(array[a].name);
}
if (array[a].description) {
array[a].description = BLI_strdup(array[a].description);
}
}
}
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (fprop->defaultarray) {
float *array = static_cast<float *>(
MEM_mallocN(sizeof(float) * prop->totarraylength, "RNA_def_property_store"));
memcpy(array, fprop->defaultarray, sizeof(float) * prop->totarraylength);
fprop->defaultarray = array;
}
break;
}
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (sprop->defaultvalue) {
sprop->defaultvalue = BLI_strdup(sprop->defaultvalue);
}
break;
}
default:
break;
}
prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
static void (*g_py_data_clear_fn)(PropertyRNA *prop) = nullptr;
/**
* Set the callback used to decrement the user count of a property.
*
* This function is called when freeing each dynamically defined property.
*/
void RNA_def_property_free_pointers_set_py_data_callback(
void (*py_data_clear_fn)(PropertyRNA *prop))
{
g_py_data_clear_fn = py_data_clear_fn;
}
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
if (g_py_data_clear_fn) {
g_py_data_clear_fn(prop);
}
if (prop->identifier) {
MEM_freeN((void *)prop->identifier);
}
if (prop->name) {
MEM_freeN((void *)prop->name);
}
if (prop->description) {
MEM_freeN((void *)prop->description);
}
if (prop->py_data) {
MEM_freeN(prop->py_data);
}
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (bprop->defaultarray) {
MEM_freeN((void *)bprop->defaultarray);
}
break;
}
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (iprop->defaultarray) {
MEM_freeN((void *)iprop->defaultarray);
}
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (fprop->defaultarray) {
MEM_freeN((void *)fprop->defaultarray);
}
break;
}
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
for (a = 0; a < eprop->totitem; a++) {
if (eprop->item[a].identifier) {
MEM_freeN((void *)eprop->item[a].identifier);
}
if (eprop->item[a].name) {
MEM_freeN((void *)eprop->item[a].name);
}
if (eprop->item[a].description) {
MEM_freeN((void *)eprop->item[a].description);
}
}
if (eprop->item) {
MEM_freeN((void *)eprop->item);
}
break;
}
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (sprop->defaultvalue) {
MEM_freeN((void *)sprop->defaultvalue);
}
break;
}
default:
break;
}
}
}
static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
if (cont->prophash) {
BLI_ghash_remove(cont->prophash, prop->identifier, nullptr, nullptr);
}
RNA_def_property_free_pointers(prop);
rna_freelinkN(&cont->properties, prop);
}
else {
RNA_def_property_free_pointers(prop);
}
}
static PropertyRNA *rna_def_property_find_py_id(ContainerRNA *cont, const char *identifier)
{
for (PropertyRNA *prop = static_cast<PropertyRNA *>(cont->properties.first); prop;
prop = prop->next)
{
if (STREQ(prop->identifier, identifier)) {
return prop;
}
}
return nullptr;
}
/* NOTE: only intended for removing dynamic props. */
int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *identifier)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop = rna_def_property_find_py_id(cont, identifier);
if (prop != nullptr) {
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
rna_def_property_free(cont, prop);
return 1;
}
else {
return -1;
}
}
return 0;
}
int RNA_def_property_free_identifier_deferred_prepare(StructOrFunctionRNA *cont_,
const char *identifier,
void **r_handle)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop = rna_def_property_find_py_id(cont, identifier);
if (prop != nullptr) {
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
*r_handle = prop;
return 1;
}
else {
return -1;
}
}
return 0;
}
void RNA_def_property_free_identifier_deferred_finish(StructOrFunctionRNA *cont_, void *handle)
{
ContainerRNA *cont = static_cast<ContainerRNA *>(cont_);
PropertyRNA *prop = static_cast<PropertyRNA *>(handle);
BLI_assert(BLI_findindex(&cont->properties, prop) != -1);
BLI_assert(prop->flag_internal & PROP_INTERN_RUNTIME);
rna_def_property_free(cont, prop);
}
#endif /* RNA_RUNTIME */
const char *RNA_property_typename(PropertyType type)
{
switch (type) {
case PROP_BOOLEAN:
return "PROP_BOOLEAN";
case PROP_INT:
return "PROP_INT";
case PROP_FLOAT:
return "PROP_FLOAT";
case PROP_STRING:
return "PROP_STRING";
case PROP_ENUM:
return "PROP_ENUM";
case PROP_POINTER:
return "PROP_POINTER";
case PROP_COLLECTION:
return "PROP_COLLECTION";
}
return "PROP_UNKNOWN";
}