This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/makesrna/intern/rna_define.c
Campbell Barton 03b2371387 Cleanup: move trailing comments to avoid wrapping code
Some statements were split across multiple lines because of their
trailing comments.

In most cases it's clearer to put the comments above.
2019-08-14 23:32:24 +10:00

4286 lines
114 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup RNA
*/
#include <float.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#include "DNA_genfile.h"
#include "DNA_sdna_types.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
#include "BLT_translation.h"
#include "UI_interface.h" /* For things like UI_PRECISION_FLOAT_MAX... */
#include "RNA_define.h"
#include "rna_internal.h"
#include "CLG_log.h"
static CLG_LogRef LOG = {"rna.define"};
#ifdef DEBUG
# 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(!"invalid soft/hard limits"); \
} \
(void)0
#else
# define ASSERT_SOFT_HARD_LIMITS (void)0
#endif
/* Global used during defining */
BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1};
#ifndef RNA_RUNTIME
static struct {
GHash *struct_map_static_from_alias;
} g_version_data;
#endif
/* Duplicated code since we can't link in blenkernel or blenlib */
/* pedantic check for final '.', note '...' are allowed though. */
#ifndef NDEBUG
# define DESCR_CHECK(description, id1, id2) \
if (description && (description)[0]) { \
int i = strlen(description); \
if (i > 3 && (description)[i - 1] == '.' && (description)[i - 3] != '.') { \
CLOG_WARN(&LOG, \
"'%s' description from '%s' '%s' ends with a '.' !", \
description, \
id1 ? id1 : "", \
id2 ? id2 : ""); \
} \
} \
(void)0
#else
# define DESCR_CHECK(description, id1, id2)
#endif
void rna_addtail(ListBase *listbase, void *vlink)
{
Link *link = vlink;
link->next = NULL;
link->prev = listbase->last;
if (listbase->last) {
((Link *)listbase->last)->next = link;
}
if (listbase->first == NULL) {
listbase->first = link;
}
listbase->last = link;
}
static void rna_remlink(ListBase *listbase, void *vlink)
{
Link *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)
{
Link *link;
for (link = listbase->first; link; link = link->next) {
PropertyRNA *prop = ((PropertyDefRNA *)link)->prop;
if (prop && (STREQ(prop->identifier, identifier))) {
return (PropertyDefRNA *)link;
}
}
return NULL;
}
void rna_freelinkN(ListBase *listbase, void *vlink)
{
rna_remlink(listbase, vlink);
MEM_freeN(vlink);
}
void rna_freelistN(ListBase *listbase)
{
Link *link, *next;
for (link = listbase->first; link; link = next) {
next = link->next;
MEM_freeN(link);
}
listbase->first = listbase->last = NULL;
}
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, NULL, NULL);
}
}
RNA_def_struct_free_pointers(NULL, srna);
if (srna->flag & STRUCT_RUNTIME) {
rna_freelinkN(&brna->structs, srna);
}
brna->structs_len -= 1;
}
#endif
static int DNA_struct_find_nr_wrapper(const struct SDNA *sdna, const char *struct_name)
{
struct_name = DNA_struct_rename_legacy_hack_static_from_alias(struct_name);
#ifdef RNA_RUNTIME
/* We may support this at some point but for now we don't. */
BLI_assert(0);
#else
struct_name = BLI_ghash_lookup_default(
g_version_data.struct_map_static_from_alias, struct_name, (void *)struct_name);
#endif
return DNA_struct_find_nr(sdna, struct_name);
}
StructDefRNA *rna_find_struct_def(StructRNA *srna)
{
StructDefRNA *dsrna;
if (!DefRNA.preprocess) {
/* we should never get here */
CLOG_ERROR(&LOG, "only at preprocess time.");
return NULL;
}
dsrna = DefRNA.structs.last;
for (; dsrna; dsrna = dsrna->cont.prev) {
if (dsrna->srna == srna) {
return dsrna;
}
}
return NULL;
}
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 NULL;
}
dsrna = rna_find_struct_def(srna);
dprop = dsrna->cont.properties.last;
for (; dprop; dprop = dprop->prev) {
if (dprop->prop == prop) {
return dprop;
}
}
dsrna = DefRNA.structs.last;
for (; dsrna; dsrna = dsrna->cont.prev) {
dprop = dsrna->cont.properties.last;
for (; dprop; dprop = dprop->prev) {
if (dprop->prop == prop) {
return dprop;
}
}
}
return NULL;
}
#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 NULL;
}
dprop = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dprop) {
return dprop;
}
dprop = rna_find_parameter_def(prop);
if (dprop) {
return dprop;
}
return NULL;
}
#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 NULL;
}
dsrna = rna_find_struct_def(DefRNA.laststruct);
dfunc = dsrna->functions.last;
for (; dfunc; dfunc = dfunc->cont.prev) {
if (dfunc->func == func) {
return dfunc;
}
}
dsrna = DefRNA.structs.last;
for (; dsrna; dsrna = dsrna->cont.prev) {
dfunc = dsrna->functions.last;
for (; dfunc; dfunc = dfunc->cont.prev) {
if (dfunc->func == func) {
return dfunc;
}
}
}
return NULL;
}
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 NULL;
}
dsrna = rna_find_struct_def(DefRNA.laststruct);
dfunc = dsrna->functions.last;
for (; dfunc; dfunc = dfunc->cont.prev) {
dparm = dfunc->cont.properties.last;
for (; dparm; dparm = dparm->prev) {
if (dparm->prop == parm) {
return dparm;
}
}
}
dsrna = DefRNA.structs.last;
for (; dsrna; dsrna = dsrna->cont.prev) {
dfunc = dsrna->functions.last;
for (; dfunc; dfunc = dfunc->cont.prev) {
dparm = dfunc->cont.properties.last;
for (; dparm; dparm = dparm->prev) {
if (dparm->prop == parm) {
return dparm;
}
}
}
}
return NULL;
}
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 NULL;
}
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 NULL;
}
/* DNA utility function for looking up members */
typedef struct DNAStructMember {
const char *type;
const char *name;
int arraylength;
int pointerlevel;
} DNAStructMember;
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 (1) {
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)
{
const char *dnaname;
const short *sp;
int a, b, structnr, totmember, cmp;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return 0;
}
structnr = DNA_struct_find_nr_wrapper(sdna, structname);
if (structnr == -1) {
return 0;
}
sp = sdna->structs[structnr];
totmember = sp[1];
sp += 2;
for (a = 0; a < totmember; a++, sp += 2) {
dnaname = sdna->alias.names[sp[1]];
cmp = rna_member_cmp(dnaname, membername);
if (cmp == 1) {
smember->type = sdna->alias.types[sp[0]];
smember->name = dnaname;
if (strstr(membername, "[")) {
smember->arraylength = 0;
}
else {
smember->arraylength = DNA_elem_array_size(smember->name);
}
smember->pointerlevel = 0;
for (b = 0; dnaname[b] == '*'; b++) {
smember->pointerlevel++;
}
return 1;
}
else if (cmp == 2) {
smember->type = "";
smember->name = dnaname;
smember->pointerlevel = 0;
smember->arraylength = 0;
membername = strstr(membername, ".") + strlen(".");
rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
return 1;
}
else if (cmp == 3) {
smember->type = "";
smember->name = dnaname;
smember->pointerlevel = 0;
smember->arraylength = 0;
membername = strstr(membername, "->") + strlen("->");
rna_find_sdna_member(sdna, sdna->alias.types[sp[0]], membername, smember);
return 1;
}
}
return 0;
}
static int rna_validate_identifier(const char *identifier, char *error, bool property)
{
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", NULL,
};
if (!isalpha(identifier[0])) {
strcpy(error, "first character failed isalpha() check");
return 0;
}
for (a = 0; identifier[a]; a++) {
if (DefRNA.preprocess && property) {
if (isalpha(identifier[a]) && isupper(identifier[a])) {
strcpy(error, "property names must contain lower case characters only");
return 0;
}
}
if (identifier[a] == '_') {
continue;
}
if (identifier[a] == ' ') {
strcpy(error, "spaces are not okay in identifier names");
return 0;
}
if (isalnum(identifier[a]) == 0) {
strcpy(error, "one of the characters failed an isalnum() check and is not an underscore");
return 0;
}
}
for (a = 0; kwlist[a]; a++) {
if (STREQ(identifier, kwlist[a])) {
strcpy(error, "this keyword is reserved by python");
return 0;
}
}
if (property) {
static const char *kwlist_prop[] = {
/* not keywords but reserved all the same because py uses */
"keys",
"values",
"items",
"get",
NULL,
};
for (a = 0; kwlist_prop[a]; a++) {
if (STREQ(identifier, kwlist_prop[a])) {
strcpy(error, "this keyword is reserved by python");
return 0;
}
}
}
return 1;
}
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", NULL,
};
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",
NULL,
};
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;
}
}
}
}
/* Blender Data Definition */
BlenderRNA *RNA_create(void)
{
BlenderRNA *brna;
brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA");
const char *error_message = NULL;
BLI_listbase_clear(&DefRNA.structs);
brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048);
DefRNA.error = 0;
DefRNA.preprocess = 1;
DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, &error_message);
if (DefRNA.sdna == NULL) {
CLOG_ERROR(&LOG, "Failed to decode SDNA: %s.", error_message);
DefRNA.error = 1;
}
/* We need both alias and static (on-disk) DNA names. */
DNA_sdna_alias_data_ensure(DefRNA.sdna);
#ifndef RNA_RUNTIME
DNA_alias_maps(DNA_RENAME_STATIC_FROM_ALIAS, &g_version_data.struct_map_static_from_alias, NULL);
#endif
return brna;
}
void RNA_define_free(BlenderRNA *UNUSED(brna))
{
StructDefRNA *ds;
FunctionDefRNA *dfunc;
AllocDefRNA *alloc;
for (alloc = DefRNA.allocs.first; alloc; alloc = alloc->next) {
MEM_freeN(alloc->mem);
}
rna_freelistN(&DefRNA.allocs);
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
for (dfunc = ds->functions.first; dfunc; dfunc = 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 = NULL;
}
DefRNA.error = 0;
}
void RNA_define_verify_sdna(bool verify)
{
DefRNA.verify = verify;
}
#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 *ext)
{
#ifdef RNA_RUNTIME
ext->free(ext->data); /* decref's the PyObject that the srna owns */
RNA_struct_blender_type_set(srna, NULL); /* this gets accessed again - XXX fixme */
/* NULL the srna's value so RNA_struct_free wont complain of a leak */
RNA_struct_py_type_set(srna, NULL);
#else
(void)srna;
(void)ext;
#endif
}
void RNA_struct_free(BlenderRNA *brna, StructRNA *srna)
{
#ifdef RNA_RUNTIME
FunctionRNA *func, *nextfunc;
PropertyRNA *prop, *nextprop;
PropertyRNA *parm, *nextparm;
# if 0
if (srna->flag & STRUCT_RUNTIME) {
if (RNA_struct_py_type_get(srna)) {
fprintf(stderr, "%s '%s' freed while holding a python reference.", srna->identifier);
}
}
# endif
for (prop = 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 = srna->functions.first; func; func = nextfunc) {
nextfunc = func->cont.next;
for (parm = 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, NULL, NULL);
brna->structs_map = NULL;
if (DefRNA.preprocess) {
RNA_define_free(brna);
for (srna = brna->structs.first; srna; srna = srna->cont.next) {
for (func = srna->functions.first; func; func = 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 = brna->structs.first; srna; srna = nextsrna) {
nextsrna = srna->cont.next;
RNA_struct_free(brna, srna);
}
}
#ifndef RNA_RUNTIME
BLI_ghash_free(g_version_data.struct_map_static_from_alias, NULL, NULL);
g_version_data.struct_map_static_from_alias = NULL;
#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 = DefRNA.structs.first; ds; ds = ds->cont.next) {
if (ds->srna == srna) {
return ds;
}
}
return NULL;
}
/* Struct Definition */
StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRNA *srnafrom)
{
StructRNA *srna;
StructDefRNA *ds = NULL, *dsfrom = NULL;
PropertyRNA *prop;
if (DefRNA.preprocess) {
char error[512];
if (rna_validate_identifier(identifier, error, false) == 0) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error);
DefRNA.error = 1;
}
}
srna = MEM_callocN(sizeof(StructRNA), "StructRNA");
DefRNA.laststruct = srna;
if (srnafrom) {
/* copy from struct to derive stuff, a bit clumsy since we can't
* use MEM_dupallocN, data structs may not be alloced but builtin */
memcpy(srna, srnafrom, sizeof(StructRNA));
srna->cont.prophash = NULL;
BLI_listbase_clear(&srna->cont.properties);
BLI_listbase_clear(&srna->functions);
srna->py_type = NULL;
srna->base = srnafrom;
if (DefRNA.preprocess) {
dsfrom = rna_find_def_struct(srnafrom);
}
else {
if (srnafrom->flag & STRUCT_PUBLIC_NAMESPACE_INHERIT) {
srna->flag |= STRUCT_PUBLIC_NAMESPACE | STRUCT_PUBLIC_NAMESPACE_INHERIT;
}
else {
srna->flag &= ~(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;
srna->flag |= STRUCT_UNDO;
}
if (DefRNA.preprocess) {
srna->flag |= STRUCT_PUBLIC_NAMESPACE;
}
rna_brna_structs_add(brna, srna);
if (DefRNA.preprocess) {
ds = MEM_callocN(sizeof(StructDefRNA), "StructDefRNA");
ds->srna = srna;
rna_addtail(&DefRNA.structs, ds);
if (dsfrom) {
ds->dnafromname = dsfrom->dnaname;
}
}
/* in preprocess, try to find sdna */
if (DefRNA.preprocess) {
RNA_def_struct_sdna(srna, srna->identifier);
}
else {
srna->flag |= STRUCT_RUNTIME;
}
if (srnafrom) {
srna->nameproperty = srnafrom->nameproperty;
srna->iteratorproperty = srnafrom->iteratorproperty;
}
else {
/* define some builtin properties */
prop = RNA_def_property(&srna->cont, "rna_properties", PROP_COLLECTION, PROP_NONE);
prop->flag_internal |= PROP_INTERN_BUILTIN;
RNA_def_property_ui_text(prop, "Properties", "RNA property collection");
if (DefRNA.preprocess) {
RNA_def_property_struct_type(prop, "Property");
RNA_def_property_collection_funcs(prop,
"rna_builtin_properties_begin",
"rna_builtin_properties_next",
"rna_iterator_listbase_end",
"rna_builtin_properties_get",
NULL,
NULL,
"rna_builtin_properties_lookup_string",
NULL);
}
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", NULL, NULL, NULL);
}
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 = NULL;
/* 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 wont link from here. */
srnafrom = BLI_ghash_lookup(brna->structs_map, from);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier);
DefRNA.error = 1;
}
}
return RNA_def_struct_ptr(brna, identifier, srnafrom);
}
void RNA_def_struct_sdna(StructRNA *srna, const char *structname)
{
StructDefRNA *ds;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
ds = rna_find_def_struct(srna);
/* There are far too many structs which initialize without valid DNA struct names,
* this can't be checked without adding an option to disable
* (tested this and it means changes all over - Campbell) */
#if 0
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
DefRNA.error = 1;
}
return;
}
#endif
ds->dnaname = structname;
}
void RNA_def_struct_sdna_from(StructRNA *srna, const char *structname, const char *propname)
{
StructDefRNA *ds;
if (!DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only during preprocessing.");
return;
}
ds = rna_find_def_struct(srna);
if (!ds->dnaname) {
CLOG_ERROR(&LOG, "%s base struct must know DNA already.", structname);
return;
}
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
DefRNA.error = 1;
}
return;
}
ds->dnafromprop = propname;
ds->dnaname = structname;
}
void RNA_def_struct_name_property(struct StructRNA *srna, struct PropertyRNA *prop)
{
if (prop->type != PROP_STRING) {
CLOG_ERROR(&LOG, "\"%s.%s\", must be a string property.", srna->identifier, prop->identifier);
DefRNA.error = 1;
}
else {
srna->nameproperty = prop;
}
}
void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *structname)
{
StructRNA *srnafrom;
/* find struct to derive from */
srnafrom = BLI_ghash_lookup(brna->structs_map, structname);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found for %s.", structname, srna->identifier);
DefRNA.error = 1;
}
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, NULL, NULL);
}
if (identifier[0] != '\0') {
BLI_ghash_insert(brna->structs_map, (void *)identifier, srna);
}
}
}
srna->identifier = identifier;
}
/**
* Only used in one case when we name the struct for the purpose of useful error messages.
*/
void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identifier)
{
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return;
}
srna->identifier = identifier;
}
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description)
{
DESCR_CHECK(description, srna->identifier, NULL);
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 = cont_;
ContainerDefRNA *dcont;
PropertyDefRNA *dprop = NULL;
PropertyRNA *prop;
if (DefRNA.preprocess) {
char error[512];
if (rna_validate_identifier(identifier, error, true) == 0) {
CLOG_ERROR(
&LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error);
DefRNA.error = 1;
}
dcont = rna_find_container_def(cont);
/* XXX - toto, detect supertype collisions */
if (rna_findlink(&dcont->properties, identifier)) {
CLOG_ERROR(&LOG, "duplicate identifier \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier);
DefRNA.error = 1;
}
dprop = MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA");
rna_addtail(&dcont->properties, dprop);
}
else {
#ifdef DEBUG
char error[512];
if (rna_validate_identifier(identifier, error, true) == 0) {
CLOG_ERROR(&LOG,
"runtime property identifier \"%s.%s\" - %s",
CONTAINER_RNA_ID(cont),
identifier,
error);
DefRNA.error = 1;
}
#endif
}
prop = MEM_callocN(rna_property_type_sizeof(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 = 1;
}
}
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 = 1;
}
#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 NULL string args, callers may clear. */
RNA_def_property_flag(prop, PROP_NEVER_NULL);
sprop->defaultvalue = "";
break;
}
case PROP_POINTER:
prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PARM_RNAPTR is set */
break;
case PROP_ENUM:
case PROP_COLLECTION:
break;
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid property type.", CONTAINER_RNA_ID(cont), identifier);
DefRNA.error = 1;
return NULL;
}
if (DefRNA.preprocess) {
dprop->cont = cont;
dprop->prop = prop;
}
prop->magic = RNA_MAGIC;
prop->identifier = identifier;
prop->type = type;
prop->subtype = subtype;
prop->name = identifier;
prop->description = "";
prop->translation_context = BLT_I18NCONTEXT_DEFAULT_BPYRNA;
/* a priori not raw editable */
prop->rawtype = -1;
if (type != PROP_COLLECTION && type != PROP_POINTER) {
prop->flag = PROP_EDITABLE;
if (type != PROP_STRING) {
#ifdef RNA_RUNTIME
prop->flag |= PROP_ANIMATABLE;
#else
if (DefRNA.animate) {
prop->flag |= PROP_ANIMATABLE;
}
#endif
}
}
if (type == PROP_STRING) {
/* used so generated 'get/length/set' functions skip a NULL check
* in some cases we want it */
RNA_def_property_flag(prop, PROP_NEVER_NULL);
}
if (DefRNA.preprocess) {
switch (type) {
case PROP_BOOLEAN:
DefRNA.silent = 1;
RNA_def_property_boolean_sdna(prop, NULL, identifier, 0);
DefRNA.silent = 0;
break;
case PROP_INT: {
DefRNA.silent = 1;
RNA_def_property_int_sdna(prop, NULL, identifier);
DefRNA.silent = 0;
break;
}
case PROP_FLOAT: {
DefRNA.silent = 1;
RNA_def_property_float_sdna(prop, NULL, identifier);
DefRNA.silent = 0;
break;
}
case PROP_STRING: {
DefRNA.silent = 1;
RNA_def_property_string_sdna(prop, NULL, identifier);
DefRNA.silent = 0;
break;
}
case PROP_ENUM:
DefRNA.silent = 1;
RNA_def_property_enum_sdna(prop, NULL, identifier);
DefRNA.silent = 0;
break;
case PROP_POINTER:
DefRNA.silent = 1;
RNA_def_property_pointer_sdna(prop, NULL, identifier);
DefRNA.silent = 0;
break;
case PROP_COLLECTION:
DefRNA.silent = 1;
RNA_def_property_collection_sdna(prop, NULL, identifier, NULL);
DefRNA.silent = 0;
break;
}
}
else {
prop->flag |= PROP_IDPROPERTY;
prop->flag_internal |= PROP_INTERN_RUNTIME;
#ifdef RNA_RUNTIME
if (cont->prophash) {
BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop);
}
#endif
}
/* Override handling. */
if (DefRNA.preprocess) {
prop->override_diff = (RNAPropOverrideDiff) "rna_property_override_diff_default";
prop->override_store = (RNAPropOverrideStore) "rna_property_override_store_default";
prop->override_apply = (RNAPropOverrideApply) "rna_property_override_apply_default";
}
/* TODO: do we want that for runtime-defined stuff too? Id say no, but... maybe yes :/ */
#ifndef RNA_RUNTIME
/* Both are typically cleared. */
RNA_def_property_update(
prop, DefRNA.fallback.property_update.noteflag, DefRNA.fallback.property_update.updatefunc);
#endif
rna_addtail(&cont->properties, prop);
return prop;
}
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag |= flag;
}
void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
{
prop->flag &= ~flag;
}
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;
}
/**
* Add the property-tags passed as \a tags to \a prop (if valid).
*
* \note Multiple tags can be set by passing them within \a tags (using bitflags).
* \note Doesn't do any type-checking with the tags defined in the parent StructRNA
* of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
*/
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 = 1;
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 = 1;
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 = 1;
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 = 1;
break;
}
}
/* common args for defaults. */
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};
/* common args for length */
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 = 1;
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 = 1;
break;
}
prop->arraydimension = dimension;
prop->totarraylength = 0;
if (length) {
memcpy(prop->arraylength, length, sizeof(int) * dimension);
prop->totarraylength = length[0];
for (i = 1; i < dimension; i++) {
prop->totarraylength *= length[i];
}
}
else {
memset(prop->arraylength, 0, sizeof(prop->arraylength));
}
/* TODO make sure arraylength values are sane */
}
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
{
DESCR_CHECK(description, prop->identifier, NULL);
prop->name = name;
prop->description = description;
}
void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, int consecutive)
{
prop->icon = icon;
if (consecutive != 0) {
prop->flag |= PROP_ICONS_CONSECUTIVE;
}
if (consecutive < 0) {
prop->flag |= PROP_ICONS_REVERSE;
}
}
/**
* The values hare are a little confusing:
*
* \param step: Used as the value to increase/decrease when clicking on number buttons,
* as well as scaling mouse input for click-dragging number buttons.
* For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
* For ints, whole values are used.
*
* \param precision: The number of zeros to show
* (as a whole number - common range is 1 - 6), see UI_PRECISION_FLOAT_MAX
*/
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 = 1;
}
if (step < 0 || step > 100) {
CLOG_ERROR(&LOG, "\"%s.%s\", step outside range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
}
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
}
#endif
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
iprop->softmin = (int)min;
iprop->softmax = (int)max;
iprop->step = (int)step;
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->softmin = (float)min;
fprop->softmax = (float)max;
fprop->step = (float)step;
fprop->precision = (int)precision;
break;
}
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for ui range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
break;
}
}
void RNA_def_property_range(PropertyRNA *prop, double min, double max)
{
StructRNA *srna = DefRNA.laststruct;
#ifdef DEBUG
if (min > max) {
CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier);
DefRNA.error = 1;
}
#endif
switch (prop->type) {
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
iprop->hardmin = (int)min;
iprop->hardmax = (int)max;
iprop->softmin = MAX2((int)min, iprop->hardmin);
iprop->softmax = MIN2((int)max, iprop->hardmax);
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprop->hardmin = (float)min;
fprop->hardmax = (float)max;
fprop->softmin = MAX2((float)min, fprop->hardmin);
fprop->softmax = MIN2((float)max, fprop->hardmax);
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid type for range.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 = 1;
break;
}
}
void RNA_def_property_struct_runtime(PropertyRNA *prop, StructRNA *type)
{
StructRNA *srna = DefRNA.laststruct;
if (DefRNA.preprocess) {
CLOG_ERROR(&LOG, "only at runtime.");
return;
}
switch (prop->type) {
case PROP_POINTER: {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
pprop->type = type;
if (type && (type->flag & STRUCT_ID_REFCOUNT)) {
prop->flag |= 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.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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: {
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] && 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 = 1;
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 = 1;
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));
bprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 = 1;
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;
iprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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;
iprop->defaultarray = array;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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;
fprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
DefRNA.error = 1;
break;
}
}
/* array must remain valid after this function finishes */
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;
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 = 1;
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 == NULL) {
CLOG_ERROR(&LOG,
"\"%s.%s\", NULL string passed (dont call in this case).",
srna->identifier,
prop->identifier);
DefRNA.error = 1;
break;
}
if (!value[0]) {
CLOG_ERROR(&LOG,
"\"%s.%s\", empty string passed (dont call in this case).",
srna->identifier,
prop->identifier);
DefRNA.error = 1;
// BLI_assert(0);
break;
}
sprop->defaultvalue = value;
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 = 1;
}
}
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 = 1;
}
}
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 == NULL) {
return NULL;
}
ds = rna_find_struct_def((StructRNA *)dp->cont);
if (!structname) {
structname = ds->dnaname;
}
if (!propname) {
propname = prop->identifier;
}
if (!rna_find_sdna_member(DefRNA.sdna, structname, propname, &smember)) {
if (DefRNA.silent) {
return NULL;
}
else 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;
}
return dp;
}
else {
CLOG_ERROR(&LOG,
"\"%s.%s\" (identifier \"%s\") not found. Struct must be in DNA.",
structname,
propname,
prop->identifier);
DefRNA.error = 1;
return NULL;
}
}
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;
return dp;
}
void RNA_def_property_boolean_sdna(PropertyRNA *prop,
const char *structname,
const char *propname,
int bit)
{
PropertyDefRNA *dp;
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 = 1;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
if (DefRNA.silent == 0) {
/* error check to ensure floats are not wrapped as ints/bools */
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 = 1;
return;
}
}
dp->booleanbit = bit;
}
}
void RNA_def_property_boolean_negative_sdna(PropertyRNA *prop,
const char *structname,
const char *propname,
int booleanbit)
{
PropertyDefRNA *dp;
RNA_def_property_boolean_sdna(prop, structname, propname, booleanbit);
dp = rna_find_struct_property_def(DefRNA.laststruct, prop);
if (dp) {
dp->booleannegative = 1;
}
}
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 = 1;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* error check to ensure floats are not wrapped as ints/bools */
if (DefRNA.silent == 0) {
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 = 1;
return;
}
}
/* SDNA doesn't pass us unsigned unfortunately .. */
if (dp->dnatype && STREQ(dp->dnatype, "char")) {
iprop->hardmin = iprop->softmin = CHAR_MIN;
iprop->hardmax = iprop->softmax = CHAR_MAX;
}
else if (dp->dnatype && STREQ(dp->dnatype, "short")) {
iprop->hardmin = iprop->softmin = SHRT_MIN;
iprop->hardmax = iprop->softmax = SHRT_MAX;
}
else if (dp->dnatype && STREQ(dp->dnatype, "int")) {
iprop->hardmin = INT_MIN;
iprop->hardmax = INT_MAX;
iprop->softmin = -10000; /* rather arbitrary .. */
iprop->softmax = 10000;
}
if (prop->subtype == PROP_UNSIGNED || prop->subtype == PROP_PERCENTAGE ||
prop->subtype == PROP_FACTOR) {
iprop->hardmin = iprop->softmin = 0;
}
}
}
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 = 1;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* silent is for internal use */
if (DefRNA.silent == 0) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
if (prop->subtype !=
PROP_COLOR_GAMMA) { /* colors are an exception. these get translated */
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 = 1;
return;
}
}
}
if (dp->dnatype && STREQ(dp->dnatype, "char")) {
fprop->hardmin = fprop->softmin = 0.0f;
fprop->hardmax = fprop->softmax = 1.0f;
}
}
rna_def_property_sdna(prop, structname, propname);
}
void RNA_def_property_enum_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_ENUM) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 = 1;
}
}
}
}
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;
}
}
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 = 1;
return;
}
if ((/* dp= */ rna_def_property_sdna(prop, structname, propname))) {
if (prop->arraydimension) {
sprop->maxlength = prop->totarraylength;
prop->arraydimension = 0;
prop->totarraylength = 0;
}
}
}
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 = 1;
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 = 1;
}
}
}
}
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 = 1;
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 = 1;
}
}
if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
cprop->next = (PropCollectionNextFunc) "rna_iterator_listbase_next";
cprop->get = (PropCollectionGetFunc) "rna_iterator_listbase_get";
cprop->end = (PropCollectionEndFunc) "rna_iterator_listbase_end";
}
}
if (dp && lengthpropname) {
DNAStructMember smember;
StructDefRNA *ds = rna_find_struct_def((StructRNA *)dp->cont);
if (!structname) {
structname = ds->dnaname;
}
if (lengthpropname[0] == 0 ||
rna_find_sdna_member(DefRNA.sdna, structname, lengthpropname, &smember)) {
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) "rna_iterator_array_next";
cprop->end = (PropCollectionEndFunc) "rna_iterator_array_end";
if (dp->dnapointerlevel >= 2) {
cprop->get = (PropCollectionGetFunc) "rna_iterator_array_dereference_get";
}
else {
cprop->get = (PropCollectionGetFunc) "rna_iterator_array_get";
}
}
else {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\" not found.", structname, lengthpropname);
DefRNA.error = 1;
}
}
}
}
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;
}
}
/**
* Set custom callbacks for override operations handling.
*
* \note \a diff callback will also be used by RNA comparison/equality functions.
*/
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, const void *func)
{
prop->update = (void *)func;
}
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func)
{
if (prop->type == PROP_POINTER) {
((PointerPropertyRNA *)prop)->poll = (void *)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 = 1;
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 = 1;
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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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 = 1;
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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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 = 1;
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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~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->itemf = (PropEnumItemFunc)item;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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->itemf = itemfunc;
}
if (getfunc || setfunc) {
/* don't save in id properties */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~PROP_EDITABLE;
}
}
}
void RNA_def_property_enum_py_data(PropertyRNA *prop, void *py_data)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
eprop->py_data = py_data;
}
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 = 1;
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 */
prop->flag &= ~PROP_IDPROPERTY;
if (!setfunc) {
prop->flag &= ~PROP_EDITABLE;
}
}
}
void RNA_def_property_pointer_funcs(
PropertyRNA *prop, const char *get, const char *set, const char *typef, 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 (typef) {
pprop->typef = (PropPointerTypeFunc)typef;
}
if (poll) {
pprop->poll = (PropPointerPollFunc)poll;
}
break;
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier);
DefRNA.error = 1;
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 = 1;
break;
}
}
void RNA_def_property_srna(PropertyRNA *prop, const char *type)
{
prop->srna = (StructRNA *)type;
}
void RNA_def_py_data(PropertyRNA *prop, void *py_data)
{
prop->py_data = py_data;
}
/* Compact definitions */
PropertyRNA *RNA_def_boolean(StructOrFunctionRNA *cont_,
const char *identifier,
bool default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_default(prop, default_value);
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_layer(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_LAYER);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_layer_member(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_LAYER_MEMBER);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_boolean_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
bool *default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_BOOLEAN, PROP_XYZ); /* XXX */
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_boolean_array_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_int(StructOrFunctionRNA *cont_,
const char *identifier,
int default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_NONE);
RNA_def_property_int_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_int_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const int *default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_XYZ); /* XXX */
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_int_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_int_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const int *default_value,
int hardmin,
int hardmax,
const char *ui_name,
const char *ui_description,
int softmin,
int softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_INT, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_int_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_string(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
BLI_assert(default_value == NULL || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_NONE);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_file_path(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
BLI_assert(default_value == NULL || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_FILEPATH);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_dir_path(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
BLI_assert(default_value == NULL || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_DIRPATH);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_string_file_name(StructOrFunctionRNA *cont_,
const char *identifier,
const char *default_value,
int maxlen,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
BLI_assert(default_value == NULL || default_value[0]);
prop = RNA_def_property(cont, identifier, PROP_STRING, PROP_FILENAME);
if (maxlen != 0) {
RNA_def_property_string_maxlength(prop, maxlen);
}
if (default_value) {
RNA_def_property_string_default(prop, default_value);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
return prop;
}
PropertyRNA *RNA_def_enum(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
int default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
if (!items) {
CLOG_ERROR(&LOG, "items not allowed to be NULL.");
return NULL;
}
prop = RNA_def_property(cont, identifier, PROP_ENUM, PROP_NONE);
if (items) {
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;
}
/* same as above but sets 'PROP_ENUM_FLAG' before setting the default value */
PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_,
const char *identifier,
const EnumPropertyItem *items,
int default_value,
const char *ui_name,
const char *ui_description)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
if (!items) {
CLOG_ERROR(&LOG, "items not allowed to be NULL.");
return NULL;
}
prop = RNA_def_property(cont, identifier, PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_FLAG); /* important to run before default set */
if (items) {
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->itemf = itemfunc;
}
PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_NONE);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_vector(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_XYZ);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
PropertyRNA *prop;
prop = RNA_def_float_vector(cont_,
identifier,
len,
default_value,
hardmin,
hardmax,
ui_name,
ui_description,
softmin,
softmax);
prop->subtype = PROP_XYZ_LENGTH;
return prop;
}
PropertyRNA *RNA_def_float_color(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_COLOR);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont_,
const char *identifier,
int rows,
int columns,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = 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_rotation(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = 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 == NULL);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 10, 3);
return prop;
}
PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
PropertyRNA *prop = RNA_def_float(cont_,
identifier,
default_value,
hardmin,
hardmax,
ui_name,
ui_description,
softmin,
softmax);
RNA_def_property_subtype(prop, PROP_DISTANCE);
return prop;
}
PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont_,
const char *identifier,
int len,
const float *default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_NONE);
if (len != 0) {
RNA_def_property_array(prop, len);
}
if (default_value) {
RNA_def_property_float_array_default(prop, default_value);
}
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_percentage(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
ASSERT_SOFT_HARD_LIMITS;
prop = RNA_def_property(cont, identifier, PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_default(prop, default_value);
if (hardmin != hardmax) {
RNA_def_property_range(prop, hardmin, hardmax);
}
RNA_def_property_ui_text(prop, ui_name, ui_description);
RNA_def_property_ui_range(prop, softmin, softmax, 1, 3);
return prop;
}
PropertyRNA *RNA_def_float_factor(StructOrFunctionRNA *cont_,
const char *identifier,
float default_value,
float hardmin,
float hardmax,
const char *ui_name,
const char *ui_description,
float softmin,
float softmax)
{
ContainerRNA *cont = 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 = 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 = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_POINTER, PROP_NONE);
RNA_def_property_struct_runtime(prop, type);
if ((type->flag & STRUCT_ID) != 0) {
prop->flag |= 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 = 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 = cont_;
PropertyRNA *prop;
prop = RNA_def_property(cont, identifier, PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_runtime(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) {
char error[512];
if (rna_validate_identifier(identifier, error, false) == 0) {
CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error);
DefRNA.error = 1;
}
}
func = MEM_callocN(sizeof(FunctionRNA), "FunctionRNA");
func->identifier = identifier;
func->description = identifier;
rna_addtail(&srna->functions, func);
if (DefRNA.preprocess) {
dsrna = rna_find_struct_def(srna);
dfunc = MEM_callocN(sizeof(FunctionDefRNA), "FunctionDefRNA");
rna_addtail(&dsrna->functions, dfunc);
dfunc->func = func;
}
else {
func->flag |= 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 NULL;
}
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;
}
/* C return value only!, multiple RNA returns can be done with RNA_def_function_output */
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;
}
else 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 == NULL);
func->c_ret = ret;
RNA_def_function_output(func, ret);
}
void RNA_def_function_output(FunctionRNA *UNUSED(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);
}
else {
return sizeof(PointerRNA *);
}
}
else {
return sizeof(void *);
}
#endif
}
case PROP_COLLECTION:
return sizeof(ListBase);
}
}
return sizeof(void *);
}
/* Dynamic Enums */
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
{
EnumPropertyItem *newitems;
int tot = *totitem;
if (tot == 0) {
*items = MEM_callocN(sizeof(EnumPropertyItem) * 8, "RNA_enum_items_add");
}
else if (tot >= 8 && (tot & (tot - 1)) == 0) {
/* power of two > 8 */
newitems = MEM_callocN(sizeof(EnumPropertyItem) * tot * 2, "RNA_enum_items_add");
memcpy(newitems, *items, sizeof(EnumPropertyItem) * tot);
MEM_freeN(*items);
*items = newitems;
}
(*items)[tot] = *item;
*totitem = tot + 1;
}
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
{
static const EnumPropertyItem sepr = {0, "", 0, NULL, NULL};
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, NULL, 0, NULL, NULL};
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);
}
srna->flag |= 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 != NULL) {
BLI_ghash_remove(brna->structs_map, (void *)srna->identifier, NULL, NULL);
}
}
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);
}
func->flag |= FUNC_FREE_POINTERS;
}
void RNA_def_func_free_pointers(FunctionRNA *func)
{
if (func->flag & FUNC_FREE_POINTERS) {
if (func->identifier) {
MEM_freeN((void *)func->identifier);
}
if (func->description) {
MEM_freeN((void *)func->description);
}
}
}
void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA *prop)
{
ContainerRNA *cont = cont_;
int a;
/* annoying since we just added this to a hash, could make this add the correct key to the hash
* in the first place */
if (prop->identifier) {
if (cont->prophash) {
prop->identifier = BLI_strdup(prop->identifier);
BLI_ghash_reinsert(cont->prophash, (void *)prop->identifier, prop, NULL, NULL);
}
else {
prop->identifier = BLI_strdup(prop->identifier);
}
}
if (prop->name) {
prop->name = BLI_strdup(prop->name);
}
if (prop->description) {
prop->description = BLI_strdup(prop->description);
}
switch (prop->type) {
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (bprop->defaultarray) {
bool *array = MEM_mallocN(sizeof(bool) * prop->totarraylength, "RNA_def_property_store");
memcpy(array, bprop->defaultarray, sizeof(bool) * prop->totarraylength);
bprop->defaultarray = array;
}
break;
}
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (iprop->defaultarray) {
int *array = MEM_mallocN(sizeof(int) * prop->totarraylength, "RNA_def_property_store");
memcpy(array, iprop->defaultarray, sizeof(int) * prop->totarraylength);
iprop->defaultarray = array;
}
break;
}
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (eprop->item) {
EnumPropertyItem *array = MEM_mallocN(sizeof(EnumPropertyItem) * (eprop->totitem + 1),
"RNA_def_property_store");
memcpy(array, eprop->item, sizeof(EnumPropertyItem) * (eprop->totitem + 1));
eprop->item = array;
for (a = 0; a < eprop->totitem; a++) {
if (array[a].identifier) {
array[a].identifier = BLI_strdup(array[a].identifier);
}
if (array[a].name) {
array[a].name = BLI_strdup(array[a].name);
}
if (array[a].description) {
array[a].description = BLI_strdup(array[a].description);
}
}
}
break;
}
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (fprop->defaultarray) {
float *array = MEM_mallocN(sizeof(float) * prop->totarraylength, "RNA_def_property_store");
memcpy(array, fprop->defaultarray, sizeof(float) * prop->totarraylength);
fprop->defaultarray = array;
}
break;
}
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (sprop->defaultvalue) {
sprop->defaultvalue = BLI_strdup(sprop->defaultvalue);
}
break;
}
default:
break;
}
prop->flag_internal |= PROP_INTERN_FREE_POINTERS;
}
void RNA_def_property_free_pointers(PropertyRNA *prop)
{
if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) {
int a;
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 = cont_;
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
if (cont->prophash) {
BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL);
}
RNA_def_property_free_pointers(prop);
rna_freelinkN(&cont->properties, prop);
}
else {
RNA_def_property_free_pointers(prop);
}
}
/* note: only intended for removing dynamic props */
int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *identifier)
{
ContainerRNA *cont = cont_;
PropertyRNA *prop;
for (prop = cont->properties.first; prop; prop = prop->next) {
if (STREQ(prop->identifier, identifier)) {
if (prop->flag_internal & PROP_INTERN_RUNTIME) {
rna_def_property_free(cont_, prop);
return 1;
}
else {
return -1;
}
}
}
return 0;
}
#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";
}