The main issue of 'type-less' standard C allocations is that there is no check on allocated type possible. This is a serious source of annoyance (and crashes) when making some low-level structs non-trivial, as tracking down all usages of these structs in higher-level other structs and their allocation is... really painful. MEM_[cm]allocN<T> templates on the other hand do check that the given type is trivial, at build time (static assert), which makes such issue... trivial to catch. NOTE: New code should strive to use MEM_new (i.e. allocation and construction) as much as possible, even for trivial PoD types. Pull Request: https://projects.blender.org/blender/blender/pulls/135870
5144 lines
146 KiB
C++
5144 lines
146 KiB
C++
/* 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 <cstdint>
|
|
#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_asan.h"
|
|
#include "BLI_ghash.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math_bits.h"
|
|
#include "BLI_string.h"
|
|
|
|
#include "BLT_translation.hh"
|
|
|
|
#include "UI_interface.hh" /* For things like UI_PRECISION_FLOAT_MAX... */
|
|
|
|
#include "RNA_define.hh"
|
|
|
|
#include "rna_internal.hh"
|
|
|
|
#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
|
|
|
|
/**
|
|
* Several types cannot use all their bytes to store a bit-set (bit-shift operations on negative
|
|
* numbers are "arithmetic", i.e. preserve the sign, i.e. are not "pure" binary shifting).
|
|
*
|
|
* Currently, all signed types and `uint64_t` cannot use their left-most bit (i.e. sign bit).
|
|
*/
|
|
#define IS_DNATYPE_BOOLEAN_BITSHIFT_FULLRANGE_COMPAT(_str) \
|
|
STR_ELEM(_str, "char", "uchar", "ushort", "uint", "uint8_t", "uint16_t", "uint32_t")
|
|
|
|
/* 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 *type_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 */
|
|
|
|
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_index_wrapper(const SDNA *sdna, const char *type_name)
|
|
{
|
|
type_name = DNA_struct_rename_legacy_hack_static_from_alias(type_name);
|
|
#ifdef RNA_RUNTIME
|
|
/* We may support this at some point but for now we don't. */
|
|
BLI_assert_unreachable();
|
|
#else
|
|
type_name = static_cast<const char *>(BLI_ghash_lookup_default(
|
|
g_version_data.type_map_static_from_alias, type_name, (void *)type_name));
|
|
#endif
|
|
return DNA_struct_find_index_without_alias(sdna, type_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_index_wrapper(sdna, structname);
|
|
|
|
smember->offset = -1;
|
|
if (structnr == -1) {
|
|
*offset = -1;
|
|
return 0;
|
|
}
|
|
|
|
const SDNA_Struct *struct_info = sdna->structs[structnr];
|
|
for (int a = 0; a < struct_info->members_num; a++) {
|
|
const SDNA_StructMember *member = &struct_info->members[a];
|
|
const int size = DNA_struct_member_size(sdna, member->type_index, member->member_index);
|
|
dnaname = sdna->alias.members[member->member_index];
|
|
cmp = rna_member_cmp(dnaname, membername);
|
|
|
|
if (cmp == 1) {
|
|
smember->type = sdna->alias.types[member->type_index];
|
|
smember->name = dnaname;
|
|
smember->offset = *offset;
|
|
smember->size = size;
|
|
|
|
if (strstr(membername, "[")) {
|
|
smember->arraylength = 0;
|
|
}
|
|
else {
|
|
smember->arraylength = DNA_member_array_num(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_index], 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;
|
|
|
|
*offset = -1;
|
|
membername = strstr(membername, "->") + strlen("->");
|
|
rna_find_sdna_member(
|
|
sdna, sdna->alias.types[member->type_index], membername, smember, offset);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (*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 (STR_ELEM(dnatype, "char", "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 = MEM_callocN<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.type_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 (srna->flag & STRUCT_RUNTIME) {
|
|
if (RNA_struct_py_type_get(srna)) {
|
|
/* NOTE: Since this is called after finalizing python/BPY in WM_exit process, it may end
|
|
* up accessing freed memory in `srna->identifier`, which will trigger an ASAN crash. */
|
|
const char *srna_identifier = "UNKNOWN";
|
|
# ifndef WITH_ASAN
|
|
srna_identifier = srna->identifier;
|
|
# endif
|
|
fprintf(stderr,
|
|
"RNA Struct definition '%s' freed while holding a Python reference.\n",
|
|
srna_identifier);
|
|
}
|
|
}
|
|
MEM_SAFE_DELETE(srna->cont.prop_lookup_set);
|
|
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.type_map_static_from_alias, nullptr, nullptr);
|
|
g_version_data.type_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 = MEM_callocN<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.prop_lookup_set = 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 = MEM_callocN<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);
|
|
srna->cont.prop_lookup_set =
|
|
MEM_new<blender::CustomIDVectorSet<PropertyRNA *, PropertyRNAIdentifierGetter>>(__func__);
|
|
}
|
|
|
|
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;
|
|
/* Properties with internal flag #PROP_INTERN_BUILTIN are not included for lookup. */
|
|
if (srna->cont.prop_lookup_set) {
|
|
srna->cont.prop_lookup_set->remove_as(prop->identifier);
|
|
}
|
|
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);
|
|
|
|
/* NOTE(@ideasman42): 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). */
|
|
#if 0
|
|
if (DNA_struct_find_index_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_index_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)
|
|
{
|
|
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 = MEM_callocN<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->prop_lookup_set) {
|
|
cont->prop_lookup_set->add(prop);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#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;
|
|
}
|
|
|
|
/* For boolean arrays using bitflags, ensure that the DNA member is an array, and not a scalar
|
|
* value.
|
|
*
|
|
* NOTE: when using #RNA_def_property_boolean_bitset_array_sdna, #RNA_def_property_array will be
|
|
* called _before_ defining #dp->booleanbit, so this check won't be triggered. */
|
|
if (DefRNA.preprocess && DefRNA.verify && prop->type == PROP_BOOLEAN) {
|
|
PropertyDefRNA *dp = rna_find_struct_property_def(DefRNA.laststruct, prop);
|
|
if (dp && dp->booleanbit && dp->dnaarraylength < length) {
|
|
CLOG_ERROR(&LOG,
|
|
"\"%s.%s\", cannot define a bitflags boolean array wrapping a scalar DNA member. "
|
|
"`RNA_def_property_boolean_bitset_array_sdna` should be used instead.",
|
|
srna->identifier,
|
|
prop->identifier);
|
|
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)
|
|
{
|
|
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 = 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;
|
|
}
|
|
|
|
static void rna_def_property_boolean_sdna(PropertyRNA *prop,
|
|
const char *structname,
|
|
const char *propname,
|
|
const int64_t booleanbit,
|
|
const bool booleannegative,
|
|
const int length)
|
|
{
|
|
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;
|
|
}
|
|
|
|
BLI_assert(length > 0);
|
|
|
|
/* In 'bitset array' case, ensure that the booleanbit value has a single bit enabled, and find
|
|
* its 'index'. */
|
|
uint bit_index = 0;
|
|
if (length > 1) {
|
|
if (booleanbit <= 0) {
|
|
CLOG_ERROR(&LOG,
|
|
"%s.%s is using a null or negative 'booleanbit' value of %" PRId64
|
|
", which is invalid "
|
|
"for 'bitset arrays' boolean properties.",
|
|
srna->identifier,
|
|
prop->identifier,
|
|
booleanbit);
|
|
DefRNA.error = true;
|
|
return;
|
|
}
|
|
|
|
bit_index = bitscan_forward_uint64(*reinterpret_cast<const uint64_t *>(&booleanbit));
|
|
if ((booleanbit & ~(1 << bit_index)) != 0) {
|
|
CLOG_ERROR(&LOG,
|
|
"%s.%s is using a multi-bit 'booleanbit' value of %" PRId64
|
|
", which is invalid for "
|
|
"'bitset arrays' boolean properties.",
|
|
srna->identifier,
|
|
prop->identifier,
|
|
booleanbit);
|
|
DefRNA.error = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
dp = rna_def_property_sdna(prop, structname, propname);
|
|
if (!dp) {
|
|
return;
|
|
}
|
|
|
|
if (!DefRNA.silent) {
|
|
/* Error check to ensure floats are not wrapped as integers/booleans. */
|
|
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;
|
|
}
|
|
}
|
|
|
|
const bool is_bitset_array = (length > 1);
|
|
if (is_bitset_array) {
|
|
if (DefRNA.verify) {
|
|
const short max_length = (dp->dnasize * 8) -
|
|
(IS_DNATYPE_BOOLEAN_BITSHIFT_FULLRANGE_COMPAT(dp->dnatype) ? 0 : 1);
|
|
if ((bit_index + length) > max_length) {
|
|
CLOG_ERROR(&LOG,
|
|
"%s.%s is a '%s' of %d bytes, but wrapped as type '%s' 'bitset array' of %d "
|
|
"items starting at bit %u.",
|
|
srna->identifier,
|
|
prop->identifier,
|
|
dp->dnatype,
|
|
dp->dnasize,
|
|
RNA_property_typename(prop->type),
|
|
length,
|
|
bit_index);
|
|
DefRNA.error = true;
|
|
return;
|
|
}
|
|
}
|
|
RNA_def_property_array(prop, length);
|
|
}
|
|
|
|
/* NOTE: #dp->booleanbit must be defined _after_ calling #RNA_def_property_array when defining a
|
|
* 'bitset array'. */
|
|
dp->booleanbit = booleanbit;
|
|
dp->booleannegative = booleannegative;
|
|
|
|
#ifndef RNA_RUNTIME
|
|
/* Set the default if possible. */
|
|
if (dp->dnaoffset != -1) {
|
|
int SDNAnr = DNA_struct_find_index_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 & booleanbit;
|
|
}
|
|
else if (STREQ(dp->dnatype, "short")) {
|
|
bprop->defaultvalue = *(const short *)default_data & booleanbit;
|
|
}
|
|
else if (STREQ(dp->dnatype, "int")) {
|
|
bprop->defaultvalue = *(const int *)default_data & booleanbit;
|
|
}
|
|
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_sdna(PropertyRNA *prop,
|
|
const char *structname,
|
|
const char *propname,
|
|
int64_t booleanbit)
|
|
{
|
|
rna_def_property_boolean_sdna(prop, structname, propname, booleanbit, false, 1);
|
|
}
|
|
|
|
void RNA_def_property_boolean_negative_sdna(PropertyRNA *prop,
|
|
const char *structname,
|
|
const char *propname,
|
|
int64_t booleanbit)
|
|
{
|
|
rna_def_property_boolean_sdna(prop, structname, propname, booleanbit, true, 1);
|
|
}
|
|
|
|
void RNA_def_property_boolean_bitset_array_sdna(PropertyRNA *prop,
|
|
const char *structname,
|
|
const char *propname,
|
|
const int64_t booleanbit,
|
|
const int length)
|
|
{
|
|
rna_def_property_boolean_sdna(prop, structname, propname, booleanbit, false, length);
|
|
}
|
|
|
|
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 integers/booleans. */
|
|
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_index_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_index_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_index_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_index_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_filepath_filter_func(PropertyRNA *prop, const char *filter)
|
|
{
|
|
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->path_filter = (StringPropertyPathFilterFunc)filter;
|
|
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_float_default_func(PropertyRNA *prop, const char *get_default)
|
|
{
|
|
StructRNA *srna = DefRNA.laststruct;
|
|
|
|
if (!DefRNA.preprocess) {
|
|
CLOG_ERROR(&LOG, "only during preprocessing");
|
|
return;
|
|
}
|
|
switch (prop->type) {
|
|
case PROP_FLOAT: {
|
|
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(prop);
|
|
if (prop->arraydimension) {
|
|
if (get_default) {
|
|
fprop->get_default_array = (PropFloatArrayGetFuncEx)get_default;
|
|
}
|
|
}
|
|
else {
|
|
if (get_default) {
|
|
fprop->get_default = (PropFloatGetFuncEx)get_default;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
|
|
DefRNA.error = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RNA_def_property_int_default_func(PropertyRNA *prop, const char *get_default)
|
|
{
|
|
StructRNA *srna = DefRNA.laststruct;
|
|
|
|
if (!DefRNA.preprocess) {
|
|
CLOG_ERROR(&LOG, "only during preprocessing");
|
|
return;
|
|
}
|
|
switch (prop->type) {
|
|
case PROP_INT: {
|
|
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(prop);
|
|
if (prop->arraydimension) {
|
|
if (get_default) {
|
|
iprop->get_default_array = (PropIntArrayGetFuncEx)get_default;
|
|
}
|
|
}
|
|
else {
|
|
if (get_default) {
|
|
iprop->get_default = (PropIntGetFuncEx)get_default;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
|
|
DefRNA.error = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RNA_def_property_boolean_default_func(PropertyRNA *prop, const char *get_default)
|
|
{
|
|
StructRNA *srna = DefRNA.laststruct;
|
|
|
|
if (!DefRNA.preprocess) {
|
|
CLOG_ERROR(&LOG, "only during preprocessing");
|
|
return;
|
|
}
|
|
switch (prop->type) {
|
|
case PROP_BOOLEAN: {
|
|
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(prop);
|
|
if (prop->arraydimension) {
|
|
if (get_default) {
|
|
bprop->get_default_array = (PropBooleanArrayGetFuncEx)get_default;
|
|
}
|
|
}
|
|
else {
|
|
if (get_default) {
|
|
bprop->get_default = (PropBooleanGetFuncEx)get_default;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", 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,
|
|
const 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,
|
|
const int len,
|
|
const 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,
|
|
const int len,
|
|
const 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,
|
|
const int len,
|
|
const 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,
|
|
const int len,
|
|
const 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,
|
|
const int default_value,
|
|
const int hardmin,
|
|
const int hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const int softmin,
|
|
const 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,
|
|
const int len,
|
|
const int *default_value,
|
|
const int hardmin,
|
|
const int hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const int softmin,
|
|
const 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,
|
|
const int len,
|
|
const int *default_value,
|
|
const int hardmin,
|
|
const int hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const int softmin,
|
|
const 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,
|
|
const 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,
|
|
const 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,
|
|
const 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,
|
|
const 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,
|
|
const 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,
|
|
const 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,
|
|
const float default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int rows,
|
|
const int columns,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const float default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const int len,
|
|
const float *default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const float default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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,
|
|
const float default_value,
|
|
const float hardmin,
|
|
const float hardmax,
|
|
const char *ui_name,
|
|
const char *ui_description,
|
|
const float softmin,
|
|
const 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 = MEM_callocN<FunctionRNA>("FunctionRNA");
|
|
func->identifier = identifier;
|
|
func->description = identifier;
|
|
|
|
rna_addtail(&srna->functions, func);
|
|
|
|
if (DefRNA.preprocess) {
|
|
dsrna = rna_find_struct_def(srna);
|
|
dfunc = MEM_callocN<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(CollectionVector);
|
|
}
|
|
}
|
|
|
|
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 = MEM_calloc_arrayN<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)
|
|
{
|
|
int a;
|
|
|
|
if (prop->identifier) {
|
|
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 = MEM_malloc_arrayN<bool>(size_t(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 = MEM_malloc_arrayN<int>(size_t(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 = MEM_malloc_arrayN<EnumPropertyItem>(size_t(eprop->totitem) + 1,
|
|
"RNA_def_property_store");
|
|
memcpy(array, eprop->item, sizeof(*array) * (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 = MEM_malloc_arrayN<float>(size_t(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->prop_lookup_set) {
|
|
cont->prop_lookup_set->remove_as(prop->identifier);
|
|
}
|
|
|
|
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";
|
|
}
|