Page MenuHome

idprop_datablock3.patch

File Metadata

Author
Tom Edwards (artfunkel)
Created
Dec 16 2013, 5:33 PM

idprop_datablock3.patch

diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index bd90960..b65d188 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -31,6 +31,7 @@
#include "DNA_ID.h"
#include "BLI_compiler_attrs.h"
+#include "BLI_ghash.h"
struct IDProperty;
struct ID;
@@ -81,8 +82,18 @@ void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append) ATTR_N
void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
/*-------- ID Type -------*/
-void IDP_LinkID(struct IDProperty *prop, ID *id);
-void IDP_UnlinkID(struct IDProperty *prop);
+
+/* Adds an IDP_ID or IDP_ARRAY property to the ID Hash Table. */
+void IDP_ID_Register(struct IDProperty *prop);
+/* Removes an IDP_ID or IDP_ARRAY property from the ID Hash Table.
+ * Use `id` to restrict unregistration of array items. */
+void IDP_ID_Unregister(struct IDProperty *prop, const ID *id);
+/* Returns a hash set of IDProperty objects which refer to the given ID */
+GHash *IDP_GetIDUsers(const ID *id);
+/* Creates or clears the ID Hash Table */
+void IDP_IDHashtable_Init();
+/* Frees the ID Hash Table and its contents */
+void IDP_IDHashtable_Free();
/*-------- Group Functions -------*/
@@ -117,7 +128,9 @@ void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(IDProperty *prop);
-void IDP_UnlinkProperty(struct IDProperty *prop);
+void IDP_UnlinkProperty(struct IDProperty *prop, struct ID *id);
+
+void IDP_RelinkProperty(struct IDProperty *prop);
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Float(prop) (*(float *)&(prop)->data.val)
@@ -125,6 +138,7 @@ void IDP_UnlinkProperty(struct IDProperty *prop);
#define IDP_String(prop) ((char *) (prop)->data.pointer)
#define IDP_Array(prop) ((prop)->data.pointer)
#define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+#define IDP_Id(prop) ((ID *) (prop)->data.pointer)
#ifdef DEBUG
/* for printout only */
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 96adade..08b6c91 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -116,6 +116,8 @@ void free_blender(void)
free_main(G.main);
G.main = NULL;
+ IDP_IDHashtable_Free();
+
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
IMB_exit();
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 594c918..afd7f0c 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -290,6 +290,10 @@ static IDProperty *IDP_CopyArray(IDProperty *prop)
{
IDProperty *newp = idp_generic_copy(prop);
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
+ newp->totallen = prop->totallen;
+
if (prop->data.pointer) {
newp->data.pointer = MEM_dupallocN(prop->data.pointer);
@@ -300,10 +304,10 @@ static IDProperty *IDP_CopyArray(IDProperty *prop)
for (a = 0; a < prop->len; a++)
array[a] = IDP_CopyProperty(array[a]);
}
+
+ if (prop->subtype == IDP_ID)
+ IDP_ID_Register(newp);
}
- newp->len = prop->len;
- newp->subtype = prop->subtype;
- newp->totallen = prop->totallen;
return newp;
}
@@ -368,6 +372,19 @@ static IDProperty *IDP_CopyString(IDProperty *prop)
return newp;
}
+static IDProperty *IDP_CopyID(IDProperty *prop)
+{
+ IDProperty *newp;
+
+ BLI_assert(prop->type == IDP_ID);
+ newp = idp_generic_copy(prop);
+
+ if (IDP_Id(prop)) {
+ IDP_Id(newp) = IDP_Id(prop);
+ IDP_ID_Register(newp);
+ }
+ return newp;
+}
void IDP_AssignString(IDProperty *prop, const char *st, int maxlen)
{
@@ -424,25 +441,105 @@ void IDP_FreeString(IDProperty *prop)
}
/** \} */
-
/* -------------------------------------------------------------------- */
-/* ID Type (not in use yet) */
+/* ID Type */
-/** \name IDProperty ID API (unused)
- * \{ */
-void IDP_LinkID(IDProperty *prop, ID *id)
+/** \name IDProperty ID API
+* \{ */
+
+static GHash *IDP_IDHashTable = NULL;
+
+static void free_idhash_value(void *val)
{
- if (prop->data.pointer) ((ID *)prop->data.pointer)->us--;
- prop->data.pointer = id;
- id_us_plus(id);
+ BLI_ghash_free(val, NULL, NULL);
}
-void IDP_UnlinkID(IDProperty *prop)
+void IDP_IDHashtable_Init()
{
- ((ID *)prop->data.pointer)->us--;
+ if (IDP_IDHashTable)
+ BLI_ghash_clear(IDP_IDHashTable, NULL, free_idhash_value);
+ else
+ IDP_IDHashTable = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+}
+void IDP_IDHashtable_Free()
+{
+ BLI_ghash_free(IDP_IDHashTable, NULL, free_idhash_value);
+ IDP_IDHashTable = NULL;
}
-/** \} */
+static GHash *find_or_create_reflist(ID *id)
+{
+ GHash *reflist = BLI_ghash_lookup(IDP_IDHashTable, id);
+ if (!reflist) {
+ reflist = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ BLI_ghash_insert(IDP_IDHashTable, id, reflist);
+ }
+ return reflist;
+}
+
+void IDP_ID_Register(IDProperty *prop)
+{
+ GHash *reflist;
+ bool new_reflist = false;
+ ID *id;
+ int i;
+
+ switch (prop->type)
+ {
+ case IDP_ID:
+ id = IDP_Id(prop);
+ if (!id) return;
+
+ reflist = find_or_create_reflist(id);
+ BLI_ghash_insert(reflist, prop, prop);
+ break;
+ case IDP_ARRAY:
+ for (i = 0; i < prop->totallen; i++) {
+ id = ((ID**) IDP_Array(prop))[i];
+ if (!id) continue;
+
+ reflist = find_or_create_reflist(id);
+
+ if (!BLI_ghash_haskey(reflist, prop))
+ BLI_ghash_insert(reflist, prop, prop);
+ }
+ break;
+ }
+}
+void IDP_ID_Unregister(IDProperty *prop, const ID *id)
+{
+ GHash *reflist = 0;
+
+ switch(prop->type) {
+ case IDP_ARRAY:
+ {
+ int i;
+ ID **id_loop = IDP_Array(prop);
+
+ if (id) reflist = BLI_ghash_lookup(IDP_IDHashTable, id);
+
+ for (i = 0; i < prop->totallen; i++) {
+ if (id_loop[i] && (!id || id_loop[i] == (ID *) id)) {
+ if (!id) reflist = BLI_ghash_lookup(IDP_IDHashTable, id_loop[i]);
+ if (reflist) BLI_ghash_remove(reflist, prop, NULL, NULL);
+ }
+ }
+ }
+ break;
+ case IDP_ID:
+ if (IDP_Id(prop) && (!id || IDP_Id(prop) == (ID *) id)) {
+ reflist = BLI_ghash_lookup(IDP_IDHashTable, id ? id : IDP_Id(prop));
+ if (reflist) BLI_ghash_remove(reflist, prop, NULL, NULL);
+ }
+ break;
+ }
+}
+
+GHash *IDP_GetIDUsers(const ID *id)
+{
+ return BLI_ghash_lookup(IDP_IDHashTable, id);
+}
+/** \} */
/* -------------------------------------------------------------------- */
/* Group Functions */
@@ -749,12 +846,64 @@ IDProperty *IDP_CopyProperty(IDProperty *prop)
switch (prop->type) {
case IDP_GROUP: return IDP_CopyGroup(prop);
case IDP_STRING: return IDP_CopyString(prop);
+ case IDP_ID: return IDP_CopyID(prop);
case IDP_ARRAY: return IDP_CopyArray(prop);
case IDP_IDPARRAY: return IDP_CopyIDPArray(prop);
default: return idp_generic_copy(prop);
}
}
+/* Updates ID pointers after an object has been copied */
+void IDP_RelinkProperty(struct IDProperty *prop)
+{
+ IDProperty *loop;
+ ID **id_loop;
+ IDProperty **idp_loop;
+ int i;
+ bool relinked_any = false;
+
+ if (!prop) return;
+
+ BLI_assert(prop->type == IDP_GROUP);
+
+ loop = prop->data.group.first;
+ while (loop) {
+ switch (loop->type)
+ {
+ case IDP_GROUP:
+ IDP_RelinkProperty(loop);
+ break;
+ case IDP_IDPARRAY:
+ idp_loop = IDP_Array(prop);
+ for (i = 0; i < prop->totallen; i++)
+ IDP_RelinkProperty(idp_loop[i]);
+ break;
+ case IDP_ARRAY:
+ if (loop->subtype != IDP_ID) break;
+ id_loop = IDP_Array(loop);
+ for (i = 0; i < loop->totallen; i++) {
+ if (id_loop[i] && id_loop[i]->newid) {
+ if (!relinked_any) {
+ IDP_ID_Unregister(loop, NULL);
+ relinked_any = true;
+ }
+ id_loop[i] = id_loop[i]->newid;
+ }
+ }
+ if (relinked_any) IDP_ID_Register(loop);
+ break;
+ case IDP_ID:
+ if (IDP_Id(loop) && IDP_Id(loop)->newid) {
+ IDP_ID_Unregister(loop, NULL);
+ IDP_Id(loop) = IDP_Id(loop)->newid;
+ IDP_ID_Register(loop);
+ }
+ break;
+ }
+ loop = loop->next;
+ }
+}
+
/**
* Get the Group property that contains the id properties for ID id. Set create_if_needed
* to create the Group property and attach it to id if it doesn't exist; otherwise
@@ -833,6 +982,8 @@ int IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const int is_s
return 0;
return 1;
}
+ case IDP_ID:
+ return IDP_Id(prop1) == IDP_Id(prop2) ? 1 : 0;
default:
/* should never get here */
BLI_assert(0);
@@ -891,11 +1042,11 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n
break;
case IDP_ARRAY:
{
- /* for now, we only support float and int and double arrays */
if ( (val->array.type == IDP_FLOAT) ||
(val->array.type == IDP_INT) ||
(val->array.type == IDP_DOUBLE) ||
- (val->array.type == IDP_GROUP) )
+ (val->array.type == IDP_GROUP) ||
+ (val->array.type == IDP_ID) )
{
prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
prop->subtype = val->array.type;
@@ -904,6 +1055,7 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n
prop->len = prop->totallen = val->array.len;
break;
}
+ printf("%s: bad array type.\n",__FUNCTION__);
return NULL;
}
case IDP_STRING:
@@ -949,6 +1101,13 @@ IDProperty *IDP_New(const int type, const IDPropertyTemplate *val, const char *n
/* heh I think all needed values are set properly by calloc anyway :) */
break;
}
+ case IDP_ID:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock");
+ IDP_Id(prop) = val->id;
+ IDP_ID_Register(prop);
+ break;
+ }
default:
{
prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
@@ -971,6 +1130,8 @@ void IDP_FreeProperty(IDProperty *prop)
{
switch (prop->type) {
case IDP_ARRAY:
+ if (prop->subtype == IDP_ID)
+ IDP_ID_Unregister(prop, NULL);
IDP_FreeArray(prop);
break;
case IDP_STRING:
@@ -982,11 +1143,15 @@ void IDP_FreeProperty(IDProperty *prop)
case IDP_IDPARRAY:
IDP_FreeIDPArray(prop);
break;
+ case IDP_ID:
+ IDP_ID_Unregister(prop, NULL);
+ break;
}
}
void IDP_ClearProperty(IDProperty *prop)
{
+ IDP_UnlinkProperty(prop, NULL);
IDP_FreeProperty(prop);
prop->data.pointer = NULL;
prop->len = prop->totallen = 0;
@@ -994,15 +1159,47 @@ void IDP_ClearProperty(IDProperty *prop)
/**
* Unlinks any struct IDProperty<->ID linkage that might be going on.
- *
- * \note currently unused
+ * Pass an id of NULL to remove all ID links.
*/
-void IDP_UnlinkProperty(IDProperty *prop)
+void IDP_UnlinkProperty(IDProperty *prop, ID *id)
{
+ int i;
+ ID **id_loop;
+ IDProperty *idp_loop;
+ void *idp_iter;
+
+ if (!prop) return;
+
switch (prop->type) {
- case IDP_ID:
- IDP_UnlinkID(prop);
- break;
+ case IDP_ID:
+ if (!id || IDP_Id(prop) == (ID *) id) {
+ IDP_ID_Unregister(prop, id);
+ IDP_Id(prop) = NULL;
+ }
+ break;
+ case IDP_ARRAY:
+ if (prop->subtype == IDP_ID) {
+ IDP_ID_Unregister(prop, id);
+
+ id_loop = IDP_Array(prop);
+ for (i = 0; i < prop->totallen; i++) {
+ if (!id || id_loop[i] == id)
+ id_loop[i] = NULL;
+ }
+ }
+ break;
+ case IDP_IDPARRAY:
+ idp_loop = IDP_Array(prop);
+ for (i = 0; i < prop->totallen; i++) {
+ IDP_UnlinkProperty(&(idp_loop[i]), id);
+ }
+ break;
+ case IDP_GROUP:
+ idp_iter = IDP_GetGroupIterator(prop);
+ while ((idp_loop = IDP_GroupIterNext(idp_iter)) != NULL) {
+ IDP_UnlinkProperty(idp_loop, id);
+ }
+ break;
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 9b8d34e..881193a 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -71,6 +71,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLF_translation.h"
@@ -866,8 +867,7 @@ void BKE_libblock_free_data(ID *id)
BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
}
-/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
-void BKE_libblock_free(ListBase *lb, void *idv)
+static void BKE_libblock_free_internal(ListBase *lb, void *idv, bool ignore_deps)
{
Main *bmain = G.main; /* should eventually be an arg */
ID *id = idv;
@@ -976,6 +976,23 @@ void BKE_libblock_free(ListBase *lb, void *idv)
break;
}
+ if (!ignore_deps) {
+ GHash *users = IDP_GetIDUsers(id);
+
+ if (users) {
+ GHashIterator *iter;
+ IDProperty *idprop;
+ iter = BLI_ghashIterator_new(users);
+ while (!BLI_ghashIterator_done(iter))
+ {
+ idprop = BLI_ghashIterator_getValue(iter);
+ BLI_ghashIterator_step(iter);
+
+ IDP_UnlinkProperty(idprop, id);
+ }
+ }
+ }
+
/* avoid notifying on removed data */
if (free_notifier_reference_cb)
free_notifier_reference_cb(id);
@@ -987,6 +1004,17 @@ void BKE_libblock_free(ListBase *lb, void *idv)
MEM_freeN(id);
}
+/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
+void BKE_libblock_free(ListBase *lb, void *idv)
+{
+ BKE_libblock_free_internal(lb, idv, false);
+}
+/* Free without worring about inter-block dependencies. Used when unloading an entire blend file. */
+void BKE_libblock_free_ignore_deps(ListBase *lb, void *idv)
+{
+ BKE_libblock_free_internal(lb, idv, true);
+}
+
void BKE_libblock_free_us(ListBase *lb, void *idv) /* test users */
{
ID *id = idv;
@@ -1018,44 +1046,44 @@ void free_main(Main *mainvar)
while ( (id = lb->first) ) {
#if 1
- BKE_libblock_free(lb, id);
+ BKE_libblock_free_ignore_deps(lb, id);
#else
/* errors freeing ID's can be hard to track down,
* enable this so valgrind will give the line number in its error log */
switch (a) {
- case 0: BKE_libblock_free(lb, id); break;
- case 1: BKE_libblock_free(lb, id); break;
- case 2: BKE_libblock_free(lb, id); break;
- case 3: BKE_libblock_free(lb, id); break;
- case 4: BKE_libblock_free(lb, id); break;
- case 5: BKE_libblock_free(lb, id); break;
- case 6: BKE_libblock_free(lb, id); break;
- case 7: BKE_libblock_free(lb, id); break;
- case 8: BKE_libblock_free(lb, id); break;
- case 9: BKE_libblock_free(lb, id); break;
- case 10: BKE_libblock_free(lb, id); break;
- case 11: BKE_libblock_free(lb, id); break;
- case 12: BKE_libblock_free(lb, id); break;
- case 13: BKE_libblock_free(lb, id); break;
- case 14: BKE_libblock_free(lb, id); break;
- case 15: BKE_libblock_free(lb, id); break;
- case 16: BKE_libblock_free(lb, id); break;
- case 17: BKE_libblock_free(lb, id); break;
- case 18: BKE_libblock_free(lb, id); break;
- case 19: BKE_libblock_free(lb, id); break;
- case 20: BKE_libblock_free(lb, id); break;
- case 21: BKE_libblock_free(lb, id); break;
- case 22: BKE_libblock_free(lb, id); break;
- case 23: BKE_libblock_free(lb, id); break;
- case 24: BKE_libblock_free(lb, id); break;
- case 25: BKE_libblock_free(lb, id); break;
- case 26: BKE_libblock_free(lb, id); break;
- case 27: BKE_libblock_free(lb, id); break;
- case 28: BKE_libblock_free(lb, id); break;
- case 29: BKE_libblock_free(lb, id); break;
- case 30: BKE_libblock_free(lb, id); break;
- case 31: BKE_libblock_free(lb, id); break;
- case 32: BKE_libblock_free(lb, id); break;
+ case 0: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 1: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 2: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 3: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 4: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 5: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 6: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 7: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 8: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 9: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 10: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 11: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 12: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 13: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 14: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 15: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 16: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 17: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 18: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 19: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 20: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 21: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 22: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 23: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 24: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 25: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 26: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 27: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 28: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 29: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 30: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 31: BKE_libblock_free_ignore_deps(lb, id); break;
+ case 32: BKE_libblock_free_ignore_deps(lb, id); break;
default:
BLI_assert(0);
break;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 047dc36..ec7dc77 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1621,24 +1621,34 @@ static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
lb->last = prev;
}
-static void test_pointer_array(FileData *fd, void **mat)
+/* Converts pointer arrays between architectures. If you don't know the number of
+* items, pass -1 and it will be inferred (dangerous, avoid if possible). */
+static void test_pointer_array(FileData *fd, void **mat, size_t items)
{
int64_t *lpoin, *lmat;
int *ipoin, *imat;
- size_t len;
+ int array_pointer_len;
/* manually convert the pointer array in
* the old dna format to a pointer array in
* the new dna format.
*/
if (*mat) {
- len = MEM_allocN_len(*mat)/fd->filesdna->pointerlen;
-
- if (fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) {
- ipoin=imat= MEM_mallocN(len * 4, "newmatar");
+ if (items == -1) {
+ array_pointer_len = fd->filesdna->pointerlen;
+ items = MEM_allocN_len(*mat) / fd->filesdna->pointerlen;
+ }
+ else {
+ /* Don't trust filesdna->pointerlen; this obscure array
+ * may have been saved blindly by an old version of Blender. */
+ array_pointer_len = MEM_allocN_len(*mat) / items;
+ }
+
+ if (array_pointer_len==8 && fd->memsdna->pointerlen==4) {
+ ipoin = imat = MEM_mallocN(items * 4, "newmatar");
lpoin= *mat;
- while (len-- > 0) {
+ while (items-- > 0) {
if ((fd->flags & FD_FLAGS_SWITCH_ENDIAN))
BLI_endian_switch_int64(lpoin);
*ipoin = (int)((*lpoin) >> 3);
@@ -1649,11 +1659,11 @@ static void test_pointer_array(FileData *fd, void **mat)
*mat = imat;
}
- if (fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) {
- lpoin = lmat = MEM_mallocN(len * 8, "newmatar");
+ if (array_pointer_len==4 && fd->memsdna->pointerlen==8) {
+ lpoin = lmat = MEM_mallocN(items * 8, "newmatar");
ipoin = *mat;
- while (len-- > 0) {
+ while (items-- > 0) {
*lpoin = *ipoin;
ipoin++;
lpoin++;
@@ -1667,7 +1677,7 @@ static void test_pointer_array(FileData *fd, void **mat)
/* ************ READ ID Properties *************** */
static void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
-static void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, FileData *fd);
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd);
static void IDP_DirectLinkIDPArray(IDProperty *prop, int switch_endian, FileData *fd)
{
@@ -1702,7 +1712,7 @@ static void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, FileData *f
prop->data.pointer = newdataadr(fd, prop->data.pointer);
if (prop->subtype == IDP_GROUP) {
- test_pointer_array(fd, prop->data.pointer);
+ test_pointer_array(fd, prop->data.pointer, prop->totallen);
array = prop->data.pointer;
for (i = 0; i < prop->len; i++)
@@ -1798,9 +1808,46 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi
}
}
-/* stub function */
-static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
+static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd)
{
+ IDProperty *loop;
+ ID **id_loop;
+ IDProperty *idp_loop;
+ int i;
+
+ if (!prop) return;
+ BLI_assert(prop->type == IDP_GROUP);
+
+ for (loop = prop->data.group.first; loop; loop = loop->next) {
+ switch (loop->type)
+ {
+ case IDP_ID: /* DatablockProperty */
+ IDP_Id(loop) = newlibadr(fd, NULL, IDP_Id(loop));
+ IDP_ID_Register(loop);
+ break;
+ case IDP_ARRAY: /* DatablockVectorProperty etc. */
+ if (loop->subtype != IDP_ID)
+ break;
+
+ test_pointer_array(fd, &IDP_Array(loop), loop->totallen);
+
+ id_loop = IDP_Array(loop);
+ for (i = 0; i < loop->totallen; i++) {
+ id_loop[i] = newlibadr(fd, NULL, id_loop[i]);
+ }
+ IDP_ID_Register(loop);
+ break;
+ case IDP_IDPARRAY: /* CollectionProperty */
+ idp_loop = IDP_Array(loop);
+ for (i = 0; i < loop->totallen; i++) {
+ IDP_LibLinkProperty(&(idp_loop[i]), fd);
+ }
+ break;
+ case IDP_GROUP: /* PointerProperty */
+ IDP_LibLinkProperty(loop, fd);
+ break;
+ }
+ }
}
/* ************ READ ID *************** */
@@ -2345,7 +2392,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
if (sock->prop)
- IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(sock->prop, fd);
}
/* singe node tree (also used for material/scene trees), ntree is not NULL */
@@ -2357,12 +2404,14 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
if (ntree->adt) lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
+
+ IDP_LibLinkProperty(ntree->id.properties, fd);
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
if (node->prop)
- IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(node->prop, fd);
node->id= newlibadr_us(fd, id->lib, node->id);
@@ -2897,10 +2946,14 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
static void lib_link_armature(FileData *fd, Main *main)
{
bArmature *arm;
+ Bone *bone;
for (arm = main->armature.first; arm; arm = arm->id.next) {
if (arm->id.flag & LIB_NEED_LINK) {
- if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt);
+ if (arm->adt)
+ lib_link_animdata(fd, &arm->id, arm->adt);
+ for (bone = arm->bonebase.first; bone; bone = bone->next)
+ IDP_LibLinkProperty(bone->prop, fd);
arm->id.flag -= LIB_NEED_LINK;
}
}
@@ -3131,7 +3184,7 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
direct_link_animdata(fd, mb->adt);
mb->mat = newdataadr(fd, mb->mat);
- test_pointer_array(fd, (void **)&mb->mat);
+ test_pointer_array(fd, (void **)&mb->mat, -1);
link_list(fd, &(mb->elems));
@@ -3274,8 +3327,6 @@ static void lib_link_image(FileData *fd, Main *main)
for (ima = main->image.first; ima; ima = ima->id.next) {
if (ima->id.flag & LIB_NEED_LINK) {
- if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-
ima->id.flag -= LIB_NEED_LINK;
}
}
@@ -3388,7 +3439,7 @@ static void direct_link_curve(FileData *fd, Curve *cu)
direct_link_animdata(fd, cu->adt);
cu->mat = newdataadr(fd, cu->mat);
- test_pointer_array(fd, (void **)&cu->mat);
+ test_pointer_array(fd, (void **)&cu->mat, -1);
cu->str = newdataadr(fd, cu->str);
cu->strinfo= newdataadr(fd, cu->strinfo);
cu->tb = newdataadr(fd, cu->tb);
@@ -3523,10 +3574,6 @@ static void lib_link_material(FileData *fd, Main *main)
if (ma->id.flag & LIB_NEED_LINK) {
if (ma->adt) lib_link_animdata(fd, &ma->id, ma->adt);
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-
ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo);
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
@@ -3967,9 +4014,6 @@ static void lib_link_mesh(FileData *fd, Main *main)
if (me->id.flag & LIB_NEED_LINK) {
int i;
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (me->adt) lib_link_animdata(fd, &me->id, me->adt);
/* this check added for python created meshes */
@@ -4139,7 +4183,7 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
static void direct_link_mesh(FileData *fd, Mesh *mesh)
{
mesh->mat= newdataadr(fd, mesh->mat);
- test_pointer_array(fd, (void **)&mesh->mat);
+ test_pointer_array(fd, (void **)&mesh->mat,-1);
mesh->mvert = newdataadr(fd, mesh->mvert);
mesh->medge = newdataadr(fd, mesh->medge);
@@ -4298,7 +4342,6 @@ static void lib_link_object(FileData *fd, Main *main)
for (ob = main->object.first; ob; ob = ob->id.next) {
if (ob->id.flag & LIB_NEED_LINK) {
- if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (ob->adt) lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
@@ -4872,7 +4915,7 @@ static void direct_link_object(FileData *fd, Object *ob)
// >>> XXX deprecated - old animation system
ob->mat= newdataadr(fd, ob->mat);
- test_pointer_array(fd, (void **)&ob->mat);
+ test_pointer_array(fd, (void **)&ob->mat,-1);
ob->matbits= newdataadr(fd, ob->matbits);
/* do it here, below old data gets converted */
@@ -4941,7 +4984,7 @@ static void direct_link_object(FileData *fd, Object *ob)
/* although not used anymore */
/* still have to be loaded to be compatible with old files */
sb->keys = newdataadr(fd, sb->keys);
- test_pointer_array(fd, (void **)&sb->keys);
+ test_pointer_array(fd, (void **)&sb->keys, sb->totkey);
if (sb->keys) {
int a;
for (a = 0; a < sb->totkey; a++) {
@@ -4986,7 +5029,7 @@ static void direct_link_object(FileData *fd, Object *ob)
for (sens = ob->sensors.first; sens; sens = sens->next) {
sens->data = newdataadr(fd, sens->data);
sens->links = newdataadr(fd, sens->links);
- test_pointer_array(fd, (void **)&sens->links);
+ test_pointer_array(fd, (void **)&sens->links, sens->totlinks);
}
direct_link_constraints(fd, &ob->constraints);
@@ -5002,7 +5045,7 @@ static void direct_link_object(FileData *fd, Object *ob)
for (cont = ob->controllers.first; cont; cont = cont->next) {
cont->data = newdataadr(fd, cont->data);
cont->links = newdataadr(fd, cont->links);
- test_pointer_array(fd, (void **)&cont->links);
+ test_pointer_array(fd, (void **)&cont->links, cont->totlinks);
if (cont->state_mask == 0)
cont->state_mask = 1;
}
@@ -5103,9 +5146,6 @@ static void lib_link_scene(FileData *fd, Main *main)
for (sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->id.flag & LIB_NEED_LINK) {
- /* Link ID Properties -- and copy this comment EXACTLY for easy finding
- * of library blocks that implement this.*/
- if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (sce->adt) lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
@@ -6558,11 +6598,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
lib->parent = NULL;
}
-static void lib_link_library(FileData *UNUSED(fd), Main *main)
+static void lib_link_library(FileData *fd, Main *main)
{
Library *lib;
for (lib = main->library.first; lib; lib = lib->id.next) {
lib->id.us = 1;
+ IDP_LibLinkProperty(lib->id.properties, fd);
}
}
@@ -6918,8 +6959,6 @@ static void lib_link_linestyle(FileData *fd, Main *main)
if (linestyle->id.flag & LIB_NEED_LINK) {
linestyle->id.flag -= LIB_NEED_LINK;
- if (linestyle->id.properties)
- IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
if (linestyle->adt)
lib_link_animdata(fd, &linestyle->id, linestyle->adt);
for (m = linestyle->color_modifiers.first; m; m = m->next) {
@@ -7454,7 +7493,24 @@ static void do_versions_after_linking(FileData *fd, Library *lib, Main *main)
static void lib_link_all(FileData *fd, Main *main)
{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int i;
+
oldnewmap_sort(fd);
+
+ i = set_listbasepointers(main, lbarray);
+ while (i--) {
+ ID *loop = lbarray[i]->first;
+
+ if (lbarray[i] == &main->nodetree)
+ continue; /* Since nodetrees aren't all in main, they do their own id-prop linking */
+
+ while (loop) {
+ if (loop->flag & LIB_NEED_LINK) /* Don't unset yet! */
+ IDP_LibLinkProperty(loop->properties, fd);
+ loop = loop->next;
+ }
+ }
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
@@ -7576,6 +7632,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
bfd->main = MEM_callocN(sizeof(Main), "readfile_Main");
+ IDP_IDHashtable_Init();
BLI_addtail(&mainlist, bfd->main);
fd->mainlist = &mainlist;
@@ -8573,6 +8630,40 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li
}
}
+static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *idprop)
+{
+ IDProperty *loop;
+ IDProperty **idp_loop;
+ ID **id_loop;
+ int i;
+
+ if (!idprop) return;
+ BLI_assert(idprop->type == IDP_GROUP);
+
+ for (loop = idprop->data.group.first; loop; loop = loop->next) {
+ switch (loop->type)
+ {
+ case IDP_ID:
+ expand_doit(fd, mainvar, IDP_Id(loop));
+ break;
+ case IDP_ARRAY:
+ if (loop->subtype != IDP_ID) break;
+ id_loop = IDP_Array(loop);
+ for (i=0; i < loop->totallen; i++)
+ expand_doit(fd, mainvar, id_loop[i]);
+ break;
+ case IDP_IDPARRAY:
+ idp_loop = IDP_Array(loop);
+ for (i = 0; i < loop->totallen; i++)
+ expand_idprops(fd, mainvar, idp_loop[i]);
+ break;
+ case IDP_GROUP:
+ expand_idprops(fd, mainvar, loop);
+ break;
+ }
+ }
+}
+
void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
{
expand_doit = expand_doit_func;
@@ -8667,6 +8758,8 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id);
break;
}
+
+ expand_idprops(fd, mainvar, id->properties);
do_it = TRUE;
id->flag -= LIB_NEED_EXPAND;
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 79db94e..3381d48 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1856,8 +1856,11 @@ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int
}
}
else if (type == PROP_POINTER) {
- /* RNA pointer */
- PointerRNA ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
+ PointerRNA ptr;
+ if (RNA_property_array_check(but->rnaprop))
+ ptr = RNA_property_pointer_get_index(&but->rnapoin, but->rnaprop, but->rnaindex);
+ else
+ ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
buf = RNA_struct_name_get_alloc(&ptr, str, maxlen, &buf_len);
}
else {
@@ -1988,18 +1991,21 @@ bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
/* RNA pointer */
PointerRNA ptr, rptr;
PropertyRNA *prop;
+ bool is_array = RNA_property_array_check(but->rnaprop);
if (str == NULL || str[0] == '\0') {
- RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL);
+ if (is_array) RNA_property_pointer_set_index(&but->rnapoin, but->rnaprop, but->rnaindex, PointerRNA_NULL);
+ else RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL);
return true;
}
else {
ptr = but->rnasearchpoin;
prop = but->rnasearchprop;
- if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr))
- RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr);
-
+ if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) {
+ if (is_array) RNA_property_pointer_set_index(&but->rnapoin, but->rnaprop, but->rnaindex, rptr);
+ else RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr);
+ }
return true;
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 8506899..e4c2ec7 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1213,7 +1213,8 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
/* property with separate label */
else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
- ui_but_add_search(but, ptr, prop, NULL, NULL);
+ if (but)
+ ui_but_add_search(but, ptr, prop, NULL, NULL);
if (layout->redalert)
uiButSetFlag(but, UI_BUT_REDALERT);
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 7da1227..d63887f 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -104,12 +104,20 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
break;
case PROP_POINTER:
{
- PointerRNA pptr;
+ PointerRNA inner;
- pptr = RNA_property_pointer_get(ptr, prop);
- if (!pptr.type)
- pptr.type = RNA_property_pointer_type(ptr, prop);
- icon = RNA_struct_ui_icon(pptr.type);
+ int len = RNA_property_array_length(ptr, prop);
+ if (len && index >= len)
+ return NULL;
+
+ if (icon == 0) {
+ if (len)
+ inner = RNA_property_pointer_get_index(ptr, prop, index);
+ else
+ inner = RNA_property_pointer_get(ptr, prop);
+
+ icon = RNA_struct_ui_icon(inner.type ? inner.type : RNA_property_pointer_type(ptr, prop));
+ }
if (icon == ICON_DOT)
icon = 0;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index b3a2a7b..6816f24 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -73,6 +73,7 @@
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_fcurve.h"
+#include "BKE_idprop.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -1755,6 +1756,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
BKE_object_relink(base->object);
+ IDP_RelinkProperty(base->object->id.properties);
}
set_sca_new_poins();
@@ -1875,6 +1877,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
id->us--;
id->newid = ob->data;
+ IDP_RelinkProperty(id->newid->properties);
}
}
@@ -2049,7 +2052,17 @@ void ED_object_single_users(Main *bmain, Scene *scene, bool full, bool copy_grou
single_mat_users_expand(bmain);
single_tex_users_expand(bmain);
}
-
+
+ IDP_RelinkProperty(scene->id.properties);
+ if (scene->nodetree) {
+ bNode *node;
+ IDP_RelinkProperty(scene->nodetree->id.properties);
+ node = scene->nodetree->nodes.first;
+ while (node) {
+ IDP_RelinkProperty(node->prop);
+ node = node->next;
+ }
+ }
clear_id_newpoins();
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index af27ea9..3db46ef 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -75,8 +75,6 @@ typedef struct IDProperty {
#define IDP_FLOAT 2
#define IDP_ARRAY 5
#define IDP_GROUP 6
-/* the ID link property type hasn't been implemented yet, this will require
- * some cleanup of blenkernel, most likely.*/
#define IDP_ID 7
#define IDP_DOUBLE 8
#define IDP_IDPARRAY 9
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index f7909d2..a684e28 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -856,7 +856,11 @@ int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
void *RNA_property_enum_py_data_get(PropertyRNA *prop);
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
+void RNA_property_pointer_get_array(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *values);
+PointerRNA RNA_property_pointer_get_index(PointerRNA *ptr, PropertyRNA *prop, int index);
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
+void RNA_property_pointer_set_array(PointerRNA *ptr, PropertyRNA *prop, const PointerRNA *values);
+void RNA_property_pointer_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, PointerRNA value);
PointerRNA RNA_property_pointer_get_default(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, CollectionPropertyIterator *iter);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 2b1a5bc..1b7f0be 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -116,6 +116,9 @@ PropertyRNA *RNA_def_pointer(StructOrFunctionRNA *cont, const char *identifier,
PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont, const char *identifier, StructRNA *type,
const char *ui_name, const char *ui_description);
+PropertyRNA *RNA_def_datablock(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type,
+ const char *ui_name, const char *ui_description);
+
PropertyRNA *RNA_def_collection(StructOrFunctionRNA *cont, const char *identifier, const char *type,
const char *ui_name, const char *ui_description);
PropertyRNA *RNA_def_collection_runtime(StructOrFunctionRNA *cont, const char *identifier, StructRNA *type,
@@ -164,7 +167,9 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
-void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
+void RNA_def_property_update_runtime(PropertyRNA *prop, void * const func);
+void RNA_def_property_poll_runtime(PropertyRNA *prop, void * const func);
+void RNA_def_property_cast_runtime(PropertyRNA *prop, void * const func);
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength);
void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const char *set);
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 43bf197..8b57f84 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -223,6 +223,9 @@ typedef enum PropertyFlag {
* note: currently no support for function arguments or non utf8 paths (filepaths) */
PROP_NEVER_CLAMP = (1 << 26),
+ /* Has a poll function defined in Python */
+ PROP_PYTHON_POLL = (1 << 28),
+
/* internal flags */
PROP_BUILTIN = (1 << 7),
PROP_EXPORT = (1 << 8),
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 1cb9eb8..19222fc 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3052,10 +3052,11 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_POINTER:
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- fprintf(f, "\t%s, %s, %s, %s,", rna_function_string(pprop->get),
+ fprintf(f, "\t%s, %s, %s, %s, %s, ", rna_function_string(pprop->get),
rna_function_string(pprop->set),
rna_function_string(pprop->typef),
- rna_function_string(pprop->poll));
+ rna_function_string(pprop->poll),
+ rna_function_string(pprop->cast));
if (pprop->type) fprintf(f, "&RNA_%s\n", (const char *)pprop->type);
else fprintf(f, "NULL\n");
break;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 075f852..521690d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -463,7 +463,16 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
#endif
- /* IDP_ID -- not implemented yet in id properties */
+ /* IDP_ID */
+ prop = RNA_def_property(srna, "datablock", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY | PROP_NEVER_UNLINK); /* no PROP_EDITABLE: ID-Properties don't
+ * provide type data needed for UI editing. */
+ RNA_def_property_struct_type(prop, "ID");
+
+ prop = RNA_def_property(srna, "datablock_array", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EXPORT | PROP_IDPROPERTY);
+ RNA_def_property_struct_type(prop, "ID");
+ RNA_def_property_array(prop, 1);
/* ID property groups > level 0, since level 0 group is merged
* with native RNA properties. the builtin_properties will take
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 1811f2e..aba3832 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -50,6 +50,7 @@
#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -377,6 +378,7 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr
return false;
break;
case IDP_GROUP:
+ case IDP_ID:
if (prop->type != PROP_POINTER)
return false;
break;
@@ -392,7 +394,8 @@ static PropertyRNA *typemap[IDP_NUMTYPES] = {
(PropertyRNA *)&rna_PropertyGroupItem_int,
(PropertyRNA *)&rna_PropertyGroupItem_float,
NULL, NULL, NULL,
- (PropertyRNA *)&rna_PropertyGroupItem_group, NULL,
+ (PropertyRNA *)&rna_PropertyGroupItem_group,
+ (PropertyRNA *)&rna_PropertyGroupItem_datablock,
(PropertyRNA *)&rna_PropertyGroupItem_double,
(PropertyRNA *)&rna_PropertyGroupItem_idp_array
};
@@ -401,7 +404,8 @@ static PropertyRNA *arraytypemap[IDP_NUMTYPES] = {
NULL, (PropertyRNA *)&rna_PropertyGroupItem_int_array,
(PropertyRNA *)&rna_PropertyGroupItem_float_array,
NULL, NULL, NULL,
- (PropertyRNA *)&rna_PropertyGroupItem_collection, NULL,
+ (PropertyRNA *)&rna_PropertyGroupItem_collection,
+ (PropertyRNA *) &rna_PropertyGroupItem_datablock_array,
(PropertyRNA *)&rna_PropertyGroupItem_double_array
};
@@ -625,7 +629,7 @@ PropertyRNA *RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
/* id prop lookup, not so common */
PropertyRNA *r_prop = NULL;
PointerRNA r_ptr; /* only support single level props */
- if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop) && (r_ptr.type == ptr->type) && (r_ptr.data == ptr->data))
+ if (RNA_path_resolve(ptr, identifier, &r_ptr, &r_prop))
return r_prop;
}
else {
@@ -1193,13 +1197,17 @@ int RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *va
if (prop->type == PROP_POINTER) {
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
- if (pprop->poll)
+
+ if (prop->flag & PROP_PYTHON_POLL) {
+ return ((PropPointerPollFuncPy) pprop->poll)(ptr, value, prop);
+ }
+ else if (pprop->poll)
return pprop->poll(ptr, *value);
return 1;
}
- printf("%s %s: is not a pointer property.\n", __func__, prop->identifier);
+ printf("%s: %s is not a pointer property.\n", __func__, prop->identifier);
return 0;
}
@@ -2681,8 +2689,10 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
if ((idprop = rna_idproperty_check(&prop, ptr))) {
pprop = (PointerPropertyRNA *)prop;
- /* for groups, data is idprop itself */
+ if (RNA_struct_is_ID(pprop->type))
+ return rna_pointer_inherit_refine(ptr, pprop->type, idprop->data.pointer);
if (pprop->typef)
+ /* for groups, data is idprop itself */
return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop);
else
return rna_pointer_inherit_refine(ptr, pprop->type, idprop);
@@ -2703,24 +2713,171 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value)
{
- /*IDProperty *idprop;*/
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *) prop;
+ BLI_assert(RNA_property_type(prop) == PROP_POINTER);
+
+ if (pprop->cast && !pprop->cast(ptr, &ptr_value, prop))
+ return;
+
+ if (ptr_value.type != NULL && !RNA_struct_is_a(ptr_value.type, pprop->type)) {
+ printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, ptr_value.type->identifier);
+ return;
+ }
+
+ if (pprop->set &&
+ !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
+ !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
+ {
+ pprop->set(ptr, ptr_value);
+ }
+ else if (prop->flag & PROP_EDITABLE) {
+ IDPropertyTemplate val = { 0 };
+ IDProperty *group;
+
+ val.id = ptr_value.data;
+
+ group = RNA_struct_idprops(ptr, 1);
+ if (group)
+ IDP_ReplaceInGroup(group, IDP_New(IDP_ID, &val, prop->identifier));
+ }
+}
+
+PointerRNA RNA_property_pointer_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ PointerRNA tmp[RNA_MAX_ARRAY_LENGTH];
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *) prop;
+ int len = rna_ensure_property_array_length(ptr, prop);
+ PointerRNA out;
+
+ BLI_assert(RNA_property_type(prop) == PROP_POINTER);
+ BLI_assert(RNA_property_array_check(prop) != false);
+ BLI_assert(index >= 0);
+
+ if (len <= RNA_MAX_ARRAY_LENGTH) {
+ RNA_property_pointer_get_array(ptr, prop, tmp);
+ out = tmp[index];
+ }
+ else {
+ PointerRNA *tmparray;
+
+ tmparray = MEM_callocN(sizeof(float) * len, "RNA_property_pointer_get_index");
+ RNA_property_pointer_get_array(ptr, prop, tmparray);
+ out = tmparray[index];
+ MEM_freeN(tmparray);
+ }
+ return out;
+}
+
+void RNA_property_pointer_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, PointerRNA value)
+{
+ PointerRNA tmp[RNA_MAX_ARRAY_LENGTH];
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
+ int len = rna_ensure_property_array_length(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_POINTER);
+ BLI_assert(RNA_property_array_check(prop) != false);
+ BLI_assert(index >= 0);
+ BLI_assert(value.type == NULL || RNA_struct_is_a(value.type, pprop->type));
+
+ if (pprop->cast && !pprop->cast(ptr, &value, prop))
+ return;
- if ((/*idprop = */ rna_idproperty_check(&prop, ptr))) {
- /* not supported */
- /* rna_idproperty_touch(idprop); */
+ if (value.type != NULL && !RNA_struct_is_a(value.type, pprop->type)) {
+ printf("%s: expected %s type, not %s.\n", __func__, pprop->type->identifier, value.type->identifier);
+ return;
+ }
+
+ if (len <= RNA_MAX_ARRAY_LENGTH) {
+ RNA_property_pointer_get_array(ptr, prop, tmp);
+ tmp[index] = value;
+ RNA_property_pointer_set_array(ptr, prop, tmp);
}
else {
- PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
+ PointerRNA *tmparray;
- if (pprop->set &&
- !((prop->flag & PROP_NEVER_NULL) && ptr_value.data == NULL) &&
- !((prop->flag & PROP_ID_SELF_CHECK) && ptr->id.data == ptr_value.id.data))
- {
- pprop->set(ptr, ptr_value);
+ tmparray = MEM_callocN(sizeof(int) * len, "RNA_property_pointer_get_index");
+ RNA_property_pointer_get_array(ptr, prop, tmparray);
+ tmparray[index] = value;
+ RNA_property_pointer_set_array(ptr, prop, tmparray);
+ MEM_freeN(tmparray);
+ }
+}
+
+/* Expands an array of ID* to PointerRNA */
+static void RNA_property_pointer_expand_array(IDProperty *idprop, StructRNA *type, PointerRNA *values)
+{
+ int i = 0;
+ ID **array = IDP_Array(idprop);
+ for ( ; i < idprop->len; i++) {
+ if (array[i] == NULL)
+ values[i] = PointerRNA_NULL;
+ else
+ RNA_pointer_create(array[i], type, array[i], &values[i]);
+ }
+}
+
+/* Condenses an array of PointerRNA to ID* */
+static void RNA_property_pointer_condense_array(IDProperty *idprop, const PointerRNA *values)
+{
+ int i = 0;
+ ID **array = IDP_Array(idprop);
+ for (; i < idprop->len; i++) {
+ array[i] = values[i].data;
+ }
+ rna_idproperty_touch(idprop);
+}
+
+void RNA_property_pointer_get_array(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *values)
+{
+ PointerPropertyRNA *pprop = (PointerPropertyRNA *) prop;
+ IDProperty *idprop;
+
+ BLI_assert(RNA_property_type(prop) == PROP_POINTER);
+ BLI_assert(RNA_property_array_check(prop) != false);
+
+ if ((idprop = rna_idproperty_check(&prop, ptr))) {
+ if (prop->arraydimension == 0)
+ values[0] = RNA_property_pointer_get(ptr, prop);
+ else {
+ RNA_property_pointer_expand_array(idprop, pprop->type, values);
}
}
+ else if (prop->arraydimension == 0)
+ values[0] = RNA_property_pointer_get(ptr, prop);
+ else
+ memset(values, 0, sizeof(PointerRNA) * prop->totarraylength);
+}
+
+void RNA_property_pointer_set_array(PointerRNA *ptr, PropertyRNA *prop, const PointerRNA *values)
+{
+ IDProperty *idprop;
+
+ BLI_assert(RNA_property_type(prop) == PROP_POINTER);
+ BLI_assert(RNA_property_array_check(prop) != false);
+
+ if ((idprop = rna_idproperty_check(&prop, ptr))) {
+ RNA_property_pointer_condense_array(idprop, values);
+ }
+ else if (prop->arraydimension == 0)
+ RNA_property_pointer_set(ptr, prop, values[0]);
+ else if (prop->flag & PROP_EDITABLE) {
+ IDPropertyTemplate val = { 0 };
+ IDProperty *group;
+
+ val.array.len = prop->totarraylength;
+ val.array.type = IDP_ID;
+
+ group = RNA_struct_idprops(ptr, 1);
+ if (group) {
+ idprop = IDP_New(IDP_ARRAY, &val, prop->identifier);
+ IDP_AddToGroup(group, idprop);
+
+ RNA_property_pointer_condense_array(idprop, values);
+ }
+ }
+
+ if (idprop)
+ IDP_ID_Register(idprop);
}
PointerRNA RNA_property_pointer_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop))
@@ -3899,15 +4056,10 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
switch (type) {
case PROP_POINTER:
nextptr = RNA_property_pointer_get(&curptr, prop);
-
- if (nextptr.data) {
- curptr = nextptr;
+ curptr = nextptr;
+ if (!use_id_prop)
prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- if (index) *index = -1;
- }
- else
- return 0;
-
+ if (index) *index = -1;
break;
case PROP_COLLECTION:
if (*path) {
@@ -5282,7 +5434,12 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
}
case PROP_POINTER:
{
- PointerRNA tptr = RNA_property_pointer_get(ptr, prop);
+ PointerRNA tptr;
+ if (RNA_property_array_check(prop))
+ tptr = RNA_property_pointer_get_index(ptr, prop, index);
+ else
+ tptr = RNA_property_pointer_get(ptr, prop);
+ if (!tptr.type) goto unknown;
cstring = RNA_pointer_as_string(C, ptr, prop, &tptr);
BLI_dynstr_append(dynstr, cstring);
MEM_freeN(cstring);
@@ -5313,6 +5470,7 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
BLI_dynstr_append(dynstr, "]");
break;
}
+ unknown:
default:
BLI_dynstr_append(dynstr, "'<UNKNOWN TYPE>'"); /* TODO */
break;
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index fe38ce2..519afb9 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1236,12 +1236,13 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
case PROP_BOOLEAN:
case PROP_INT:
case PROP_FLOAT:
+ case PROP_POINTER:
prop->arraylength[0] = length;
prop->totarraylength = length;
prop->arraydimension = 1;
break;
default:
- fprintf(stderr, "%s: \"%s.%s\", only boolean/int/float can be array.\n",
+ fprintf(stderr, "%s: \"%s.%s\", only boolean/int/float/pointer can be array.\n",
__func__, srna->identifier, prop->identifier);
DefRNA.error = 1;
break;
@@ -2124,11 +2125,27 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
prop->update = (UpdateFunc)func;
}
-void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
+void RNA_def_property_update_runtime(PropertyRNA *prop, void * const func)
{
prop->update = func;
}
+void RNA_def_property_poll_runtime(PropertyRNA *prop, void * const func)
+{
+ if (prop->type == PROP_POINTER)
+ ((PointerPropertyRNA *)prop)->poll = func;
+ else
+ fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
+}
+
+void RNA_def_property_cast_runtime(PropertyRNA *prop, void * const func)
+{
+ if (prop->type == PROP_POINTER)
+ ((PointerPropertyRNA *)prop)->cast = func;
+ else
+ fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier);
+}
+
void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getlength)
{
if (!DefRNA.preprocess) {
@@ -2928,6 +2945,20 @@ PropertyRNA *RNA_def_pointer_runtime(StructOrFunctionRNA *cont_, const char *ide
return prop;
}
+PropertyRNA *RNA_def_datablock(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);
+ 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)
{
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 807fad4..ae4a858 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -329,6 +329,8 @@ extern IntPropertyRNA rna_PropertyGroupItem_int_array;
extern FloatPropertyRNA rna_PropertyGroupItem_float;
extern FloatPropertyRNA rna_PropertyGroupItem_float_array;
extern PointerPropertyRNA rna_PropertyGroupItem_group;
+extern PointerPropertyRNA rna_PropertyGroupItem_datablock;
+extern PointerPropertyRNA rna_PropertyGroupItem_datablock_array;
extern CollectionPropertyRNA rna_PropertyGroupItem_collection;
extern CollectionPropertyRNA rna_PropertyGroupItem_idp_array;
extern FloatPropertyRNA rna_PropertyGroupItem_double;
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 1dce89c..b16f958 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -96,6 +96,8 @@ typedef PointerRNA (*PropPointerGetFunc)(struct PointerRNA *ptr);
typedef StructRNA *(*PropPointerTypeFunc)(struct PointerRNA *ptr);
typedef void (*PropPointerSetFunc)(struct PointerRNA *ptr, const PointerRNA value);
typedef int (*PropPointerPollFunc)(struct PointerRNA *ptr, const PointerRNA value);
+typedef int (*PropPointerPollFuncPy)(struct PointerRNA *ptr, PointerRNA *value, const PropertyRNA *prop);
+typedef int (*PropPointerCastFunc)(struct PointerRNA *ptr, PointerRNA *value, const PropertyRNA *prop);
typedef void (*PropCollectionBeginFunc)(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
typedef void (*PropCollectionNextFunc)(struct CollectionPropertyIterator *iter);
typedef void (*PropCollectionEndFunc)(struct CollectionPropertyIterator *iter);
@@ -315,6 +317,7 @@ typedef struct PointerPropertyRNA {
PropPointerSetFunc set;
PropPointerTypeFunc typef;
PropPointerPollFunc poll; /* unlike operators, 'set' can still run if poll fails, used for filtering display */
+ PropPointerCastFunc cast; /* Python-only func to convert data (e.g. a custom PropertyGroup) to the correct type */
struct StructRNA *type;
} PointerPropertyRNA;
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index c3cbe7d..46ec51b 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -37,6 +37,9 @@
#include "BKE_idprop.h"
+extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
+extern bool pyrna_id_CheckPyObject(PyObject *obj);
+extern PyObject *pyrna_id_CreatePyObject(ID *id);
#define USE_STRING_COERCE
@@ -88,6 +91,11 @@ static PyObject *idprop_py_from_idp_group(ID *id, IDProperty *prop, IDProperty *
return (PyObject *)group;
}
+static PyObject *idprop_py_from_idp_id(ID *id, IDProperty *prop)
+{
+ return pyrna_id_CreatePyObject(prop->data.pointer);
+}
+
static PyObject *idprop_py_from_idp_array(ID *id, IDProperty *prop)
{
BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &BPy_IDArray_Type);
@@ -145,6 +153,7 @@ PyObject *BPy_IDGroup_WrapData(ID *id, IDProperty *prop, IDProperty *parent)
case IDP_GROUP: return idprop_py_from_idp_group(id, prop, parent);
case IDP_ARRAY: return idprop_py_from_idp_array(id, prop);
case IDP_IDPARRAY: return idprop_py_from_idp_idparray(id, prop); /* this could be better a internal type */
+ case IDP_ID: return idprop_py_from_idp_id(id, prop);
default: Py_RETURN_NONE;
}
}
@@ -316,6 +325,12 @@ static int idp_sequence_type(PyObject *seq_fast)
return -1;
}
}
+ else if (item == Py_None || pyrna_id_CheckPyObject(item)) {
+ if (i != 0 && type != IDP_ID) { /* mixed dict/int */
+ return -1;
+ }
+ type = IDP_ID;
+ }
else if (PyMapping_Check(item)) {
if (i != 0 && (type != IDP_IDPARRAY)) { /* mixed dict/int */
return -1;
@@ -406,7 +421,7 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
if ((val.array.type = idp_sequence_type(ob_seq_fast)) == -1) {
Py_DECREF(ob_seq_fast);
- PyErr_SetString(PyExc_TypeError, "only floats, ints and dicts are allowed in ID property arrays");
+ PyErr_SetString(PyExc_TypeError, "ID property arrays must consist entirely of ONE of the following types: float, int, datablock, dict");
return false;
}
@@ -446,6 +461,18 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
}
break;
}
+ case IDP_ID:
+ {
+ ID ** prop_data;
+ prop = IDP_New(IDP_ARRAY, &val, name);
+ prop_data = (ID **)IDP_Array(prop);
+
+ for (i = 0; i < val.array.len; i++) {
+ pyrna_id_FromPyObject(PySequence_Fast_GET_ITEM(ob_seq_fast, i), &(prop_data[i])); /* NB the brackets defining execution order! */
+ }
+ IDP_ID_Register(prop);
+ break;
+ }
case IDP_IDPARRAY:
{
prop = IDP_NewIDPArray(name);
@@ -468,6 +495,9 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
Py_DECREF(ob_seq_fast);
}
+ else if (ob == Py_None || pyrna_id_FromPyObject(ob, &val.id)) {
+ prop = IDP_New(IDP_ID, &val, name);
+ }
else if (PyMapping_Check(ob)) {
PyObject *keys, *vals, *key, *pval;
int i, len;
@@ -475,32 +505,36 @@ bool BPy_IDProperty_Map_ValidateAndCreate(PyObject *name_obj, IDProperty *group,
keys = PyMapping_Keys(ob);
vals = PyMapping_Values(ob);
- /* we allocate the group first; if we hit any invalid data,
- * we can delete it easily enough.*/
- prop = IDP_New(IDP_GROUP, &val, name);
len = PyMapping_Length(ob);
- for (i = 0; i < len; i++) {
- key = PySequence_GetItem(keys, i);
- pval = PySequence_GetItem(vals, i);
- if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
- IDP_FreeProperty(prop);
- MEM_freeN(prop);
- Py_XDECREF(keys);
- Py_XDECREF(vals);
+ if (len != -1)
+ {
+ /* we allocate the group first; if we hit any invalid data,
+ * we can delete it easily enough.*/
+ prop = IDP_New(IDP_GROUP, &val, name);
+ for (i = 0; i < len; i++) {
+ key = PySequence_GetItem(keys, i);
+ pval = PySequence_GetItem(vals, i);
+ if (BPy_IDProperty_Map_ValidateAndCreate(key, prop, pval) == false) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ /* error is already set */
+ return false;
+ }
Py_XDECREF(key);
Py_XDECREF(pval);
- /* error is already set */
- return false;
}
- Py_XDECREF(key);
- Py_XDECREF(pval);
}
Py_XDECREF(keys);
Py_XDECREF(vals);
}
- else {
+
+ if (!prop) {
PyErr_Format(PyExc_TypeError,
- "invalid id-property type %.200s not supported",
+ "invalid id-property: type %.200s not supported",
Py_TYPE(ob)->tp_name);
return false;
}
@@ -621,6 +655,14 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
}
break;
}
+ case IDP_ID:
+ {
+ ID **array = (ID **)IDP_Array(prop);
+ for (i = 0; i < prop->len; i++) {
+ PyList_SET_ITEM(seq, i, pyrna_id_CreatePyObject(array[i]));
+ }
+ break;
+ }
default:
PyErr_Format(PyExc_RuntimeError,
"%s: invalid/corrupt array type '%d'!",
@@ -1031,6 +1073,7 @@ static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
case IDP_FLOAT: return PyUnicode_FromString("f");
case IDP_DOUBLE: return PyUnicode_FromString("d");
case IDP_INT: return PyUnicode_FromString("i");
+ case IDP_ID: return BPy_IDArray_repr(self);
}
PyErr_Format(PyExc_RuntimeError,
@@ -1076,6 +1119,8 @@ static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
return PyFloat_FromDouble(((double *)IDP_Array(self->prop))[index]);
case IDP_INT:
return PyLong_FromLong((long)((int *)IDP_Array(self->prop))[index]);
+ case IDP_ID:
+ return pyrna_id_CreatePyObject(((ID **)IDP_Array(self->prop))[index]);
}
PyErr_Format(PyExc_RuntimeError,
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index bfa4954..dff3dcc 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -50,11 +50,13 @@
#include "../generic/py_capi_utils.h"
/* initial definition of callback slots we'll probably have more than 1 */
-#define BPY_DATA_CB_SLOT_SIZE 3
+#define BPY_DATA_CB_SLOT_SIZE 5
#define BPY_DATA_CB_SLOT_UPDATE 0
#define BPY_DATA_CB_SLOT_GET 1
#define BPY_DATA_CB_SLOT_SET 2
+#define BPY_DATA_CB_SLOT_POLL 3
+#define BPY_DATA_CB_SLOT_CAST 4
extern BPy_StructRNA *bpy_context_module;
@@ -125,6 +127,8 @@ static PyObject *pymeth_FloatVectorProperty = NULL;
static PyObject *pymeth_StringProperty = NULL;
static PyObject *pymeth_EnumProperty = NULL;
static PyObject *pymeth_PointerProperty = NULL;
+static PyObject *pymeth_DatablockProperty = NULL;
+static PyObject *pymeth_DatablockVectorProperty = NULL;
static PyObject *pymeth_CollectionProperty = NULL;
static PyObject *pymeth_RemoveProperty = NULL;
@@ -350,6 +354,111 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
}
}
+static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA *candidate, struct PropertyRNA *prop)
+{
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject **py_data = (PyObject **) RNA_property_py_data_get(prop);
+ PyObject *args;
+ PyObject *ret;
+ bool out;
+ PyGILState_STATE gilstate;
+ const int is_write_ok = pyrna_write_check();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(candidate);
+ py_func = py_data[BPY_DATA_CB_SLOT_POLL];
+
+ if (!is_write_ok)
+ pyrna_write_set(true);
+ gilstate = PyGILState_Ensure();
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ printf_func_error(py_func);
+ out = false;
+ }
+ else
+ {
+ out = PyObject_IsTrue(ret);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok)
+ pyrna_write_set(false);
+
+ return out;
+}
+
+static bool bpy_prop_cast_cb(struct PointerRNA *self, PointerRNA *candidate, struct PropertyRNA *prop)
+{
+ PyObject *py_self;
+ PyObject *py_candidate;
+ PyObject *py_func;
+ PyObject **py_data = (PyObject **) RNA_property_py_data_get(prop);
+ PyObject *args;
+ PyObject *ret;
+ PyGILState_STATE gilstate;
+ const int is_write_ok = pyrna_write_check();
+
+ BLI_assert(self != NULL);
+
+ py_self = pyrna_struct_as_instance(self);
+ py_candidate = pyrna_struct_as_instance(candidate);
+ py_func = py_data[BPY_DATA_CB_SLOT_CAST];
+
+ if (!is_write_ok)
+ pyrna_write_set(true);
+ gilstate = PyGILState_Ensure();
+
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 0, py_self);
+ PyTuple_SET_ITEM(args, 1, py_candidate);
+
+ ret = PyObject_CallObject(py_func, args);
+
+ Py_DECREF(args);
+
+ if (ret == NULL) {
+ printf_func_error(py_func);
+ return false;
+ }
+ else if (ret == Py_None) {
+ *candidate = PointerRNA_NULL;
+ }
+ else
+ {
+ ID *id;
+ pyrna_id_FromPyObject(ret, &id);
+ if (id == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "return value must be %.200s or None, not %.200s",
+ RNA_struct_ui_name(RNA_property_pointer_type(self,prop)), Py_TYPE(ret)->tp_name);
+ printf_func_error(py_func);
+ return false;
+ }
+ RNA_pointer_create(id, ((BPy_StructRNA *) ret)->ptr.type, id, candidate);
+ Py_DECREF(ret);
+ }
+
+ PyGILState_Release(gilstate);
+ if (!is_write_ok)
+ pyrna_write_set(false);
+
+ return true;
+}
+
static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop, int *values)
{
PyObject **py_data = (PyObject **)RNA_property_py_data_get(prop);
@@ -1540,6 +1649,28 @@ static void bpy_prop_callback_assign_update(struct PropertyRNA *prop, PyObject *
RNA_def_property_flag(prop, PROP_CONTEXT_PROPERTY_UPDATE);
}
}
+static void bpy_prop_callback_assign_poll(struct PropertyRNA *prop, PyObject *poll_cb)
+{
+ /* assume this is already checked for type and arg length */
+ if (poll_cb && poll_cb != Py_None) {
+ PyObject **py_data = bpy_prop_py_data_get(prop);
+
+ RNA_def_property_poll_runtime(prop, (void *)bpy_prop_poll_cb);
+ py_data[BPY_DATA_CB_SLOT_POLL] = poll_cb;
+
+ RNA_def_property_flag(prop, PROP_PYTHON_POLL);
+ }
+}
+static void bpy_prop_callback_assign_cast(struct PropertyRNA *prop, PyObject *cast_cb)
+{
+ /* assume this is already checked for type and arg length */
+ if (cast_cb && cast_cb != Py_None) {
+ PyObject **py_data = bpy_prop_py_data_get(prop);
+
+ RNA_def_property_cast_runtime(prop, (void *)bpy_prop_cast_cb);
+ py_data[BPY_DATA_CB_SLOT_CAST] = cast_cb;
+ }
+}
static void bpy_prop_callback_assign_boolean(struct PropertyRNA *prop, PyObject *get_cb, PyObject *set_cb)
{
@@ -2647,32 +2778,32 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix)
+static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix, StructRNA *type)
{
StructRNA *srna;
-
+
srna = srna_from_self(value, "");
if (!srna) {
if (PyErr_Occurred()) {
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with: %s",
- error_prefix, msg_char);
+ "%.200s expected an RNA type derived from %.200s, failed with: %s",
+ error_prefix, RNA_struct_ui_name(type), msg_char);
Py_DECREF(msg);
}
else {
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup, failed with type '%s'",
- error_prefix, Py_TYPE(value)->tp_name);
+ "%.200s expected an RNA type derived from %.200s, failed with type '%s'",
+ error_prefix, RNA_struct_ui_name(type), Py_TYPE(value)->tp_name);
}
return NULL;
}
- if (!RNA_struct_is_a(srna, &RNA_PropertyGroup)) {
+ if (!RNA_struct_is_a(srna, type)) {
PyErr_Format(PyExc_TypeError,
- "%.200s expected an RNA type derived from PropertyGroup",
- error_prefix);
+ "%.200s expected an RNA type derived from %.200s",
+ error_prefix, RNA_struct_ui_name(type));
return NULL;
}
@@ -2724,7 +2855,7 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
BPY_PROPDEF_CHECK(PointerProperty, property_flag_items);
- ptype = pointer_type_from_py(type, "PointerProperty(...):");
+ ptype = pointer_type_from_py(type, "PointerProperty(...):", &RNA_PropertyGroup);
if (!ptype)
return NULL;
@@ -2745,6 +2876,160 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
Py_RETURN_NONE;
}
+PyDoc_STRVAR(BPy_DatablockProperty_doc,
+ ".. function :: DatablockProperty(type, name="", description="", options=None, update=None, poll=None, cast=None)\n"
+ " Returns a new Datablock property definition.\n"
+ "\n"
+ " :arg type: A subclass of :class:`bpy.types.ID`.\n"
+ " :type type: class\n"
+ BPY_PROPDEF_NAME_DOC
+ BPY_PROPDEF_DESC_DOC
+ " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'LIBRARY_EDITABLE'].\n"
+ " :type options: set\n"
+ BPY_PROPDEF_UPDATE_DOC
+ " :arg poll: function to be called to determine whether an item is valid for this property.\n"
+ " The function must take 2 values (self,object) and return Bool.\n"
+ " :type poll: function\n"
+ " :arg cast: function to be called to convert values prior to assignment to this property.\n"
+ " The function must take 2 values (self,object) and return an object compatible with the value of `type` or None.\n"
+ " :type cast: function\n"
+ );
+static PyObject *BPy_DatablockProperty(PyObject *self, PyObject *args, PyObject *kw)
+{
+ StructRNA *srna;
+
+ BPY_PROPDEF_HEAD(DatablockProperty);
+
+ if (srna) {
+ static const char *kwlist[] = { "attr", "type", "name", "description", "options", "update", "poll", "cast", NULL };
+ const char *id = NULL, *name = NULL, *description = "";
+ int id_len;
+ PropertyRNA *prop;
+ PyObject *type = Py_None;
+ StructRNA *ptype;
+ PyObject *pyopts = NULL;
+ int opts = 0;
+ PyObject *update_cb = NULL, *poll_cb = NULL, *cast_cb = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw,
+ "s#O|ssO!OOO:DatablockProperty",
+ (char **) kwlist, &id, &id_len,
+ &type, &name, &description,
+ &PySet_Type, &pyopts,
+ &update_cb, &poll_cb, &cast_cb))
+ {
+ return NULL;
+ }
+
+ BPY_PROPDEF_CHECK(DatablockProperty, property_flag_items);
+
+ ptype = pointer_type_from_py(type, "DatablockProperty(...):", &RNA_ID);
+ if (!ptype)
+ return NULL;
+
+ if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ return NULL;
+ }
+ if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ return NULL;
+ }
+ if (bpy_prop_callback_check(cast_cb, "cast", 2) == -1) {
+ return NULL;
+ }
+
+ prop = RNA_def_datablock(srna, id, ptype, name ? name : id, description);
+ if (pyopts) {
+ if (opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
+ if (opts & PROP_SKIP_SAVE) RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ if (opts & PROP_LIB_EXCEPTION) RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ }
+ bpy_prop_callback_assign_update(prop, update_cb);
+ bpy_prop_callback_assign_poll(prop, poll_cb);
+ bpy_prop_callback_assign_cast(prop, cast_cb);
+ RNA_def_property_duplicate_pointers(srna, prop);
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(BPy_DatablockVectorProperty_doc,
+ ".. function :: DatablockVectorProperty(type, size, name="", description="", options=None, update=None, poll=None)\n"
+ " Returns a new Datablock property definition.\n"
+ "\n"
+ " :arg type: A subclass of :class:`bpy.types.ID`.\n"
+ " :type type: class\n"
+ " :arg size: Vector length in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
+ " :type size: int\n"
+ BPY_PROPDEF_NAME_DOC
+ BPY_PROPDEF_DESC_DOC
+ " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'LIBRARY_EDITABLE'].\n"
+ " :type options: set\n"
+ BPY_PROPDEF_UPDATE_DOC
+ " :arg poll: function to be called to determine whether an item is valid for this property.\n"
+ " The function must take 2 values (self,object) and return Bool.\n"
+ " :type poll: function\n"
+ " :arg cast: function to be called to convert values prior to assignment to this property.\n"
+ " The function must take 2 values (self,object) and return an object compatible with the value of `type` or None.\n"
+ " :type cast: function\n"
+ );
+static PyObject *BPy_DatablockVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
+{
+ StructRNA *srna;
+
+ BPY_PROPDEF_HEAD(DatablockVectorProperty);
+
+ if (srna) {
+ static const char *kwlist[] = { "attr", "type", "size", "name", "description", "options", "update", "poll", "cast", NULL };
+ const char *id = NULL, *name = NULL, *description = "";
+ int id_len;
+ PropertyRNA *prop;
+ PyObject *type = Py_None;
+ StructRNA *ptype;
+ PyObject *pyopts = NULL;
+ int opts = 0;
+ int size;
+ PyObject *update_cb = NULL, *poll_cb = NULL, *cast_cb = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw,
+ "s#Oi|ssO!OOO:DatablockVectorProperty",
+ (char **) kwlist, &id, &id_len,
+ &type, &size, &name, &description,
+ &PySet_Type, &pyopts,
+ &update_cb, &poll_cb, &cast_cb))
+ {
+ return NULL;
+ }
+
+ BPY_PROPDEF_CHECK(DatablockVectorProperty, property_flag_items);
+
+ ptype = pointer_type_from_py(type, "DatablockVectorProperty(...):", &RNA_ID);
+ if (!ptype)
+ return NULL;
+
+ if (bpy_prop_callback_check(update_cb, "update", 2) == -1) {
+ return NULL;
+ }
+ if (bpy_prop_callback_check(poll_cb, "poll", 2) == -1) {
+ return NULL;
+ }
+ if (bpy_prop_callback_check(cast_cb, "cast", 2) == -1) {
+ return NULL;
+ }
+
+ prop = RNA_def_datablock(srna, id, ptype, name ? name : id, description);
+ RNA_def_property_array(prop, size);
+ if (pyopts) {
+ if (opts & PROP_HIDDEN) RNA_def_property_flag(prop, PROP_HIDDEN);
+ if (opts & PROP_SKIP_SAVE) RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ if (opts & PROP_LIB_EXCEPTION) RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
+ }
+ bpy_prop_callback_assign_update(prop, update_cb);
+ bpy_prop_callback_assign_poll(prop, poll_cb);
+ bpy_prop_callback_assign_cast(prop, cast_cb);
+ RNA_def_property_duplicate_pointers(srna, prop);
+ }
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(BPy_CollectionProperty_doc,
".. function:: CollectionProperty(items, "
"type=\"\", "
@@ -2787,7 +3072,7 @@ static PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject
BPY_PROPDEF_CHECK(CollectionProperty, property_flag_items);
- ptype = pointer_type_from_py(type, "CollectionProperty(...):");
+ ptype = pointer_type_from_py(type, "CollectionProperty(...):", &RNA_PropertyGroup);
if (!ptype)
return NULL;
@@ -2871,6 +3156,8 @@ static struct PyMethodDef props_methods[] = {
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS | METH_KEYWORDS, BPy_StringProperty_doc},
{"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS | METH_KEYWORDS, BPy_EnumProperty_doc},
{"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS | METH_KEYWORDS, BPy_PointerProperty_doc},
+ {"DatablockProperty", (PyCFunction)BPy_DatablockProperty, METH_VARARGS | METH_KEYWORDS, BPy_DatablockProperty_doc},
+ {"DatablockVectorProperty", (PyCFunction)BPy_DatablockVectorProperty, METH_VARARGS | METH_KEYWORDS, BPy_DatablockVectorProperty_doc},
{"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS | METH_KEYWORDS, BPy_CollectionProperty_doc},
{"RemoveProperty", (PyCFunction)BPy_RemoveProperty, METH_VARARGS | METH_KEYWORDS, BPy_RemoveProperty_doc},
@@ -2914,6 +3201,8 @@ PyObject *BPY_rna_props(void)
ASSIGN_STATIC(StringProperty);
ASSIGN_STATIC(EnumProperty);
ASSIGN_STATIC(PointerProperty);
+ ASSIGN_STATIC(DatablockProperty);
+ ASSIGN_STATIC(DatablockVectorProperty);
ASSIGN_STATIC(CollectionProperty);
ASSIGN_STATIC(RemoveProperty);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 5a87870..0821c41 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -1809,24 +1809,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
}
}
else {
- /* data == NULL, assign to RNA */
- if (value == Py_None) {
- PointerRNA valueptr = {{NULL}};
- RNA_property_pointer_set(ptr, prop, valueptr);
- }
- else if (RNA_struct_is_a(param->ptr.type, ptr_type)) {
- RNA_property_pointer_set(ptr, prop, param->ptr);
- }
- else {
- PointerRNA tmp;
- RNA_pointer_create(NULL, ptr_type, NULL, &tmp);
- PyErr_Format(PyExc_TypeError,
- "%.200s %.200s.%.200s expected a %.200s type. not %.200s",
- error_prefix, RNA_struct_identifier(ptr->type),
- RNA_property_identifier(prop), RNA_struct_identifier(tmp.type),
- RNA_struct_identifier(param->ptr.type));
- Py_XDECREF(value_new); return -1;
- }
+ /* no special case, just hand off to the property */
+ RNA_property_pointer_set(ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr);
}
if (raise_error) {
@@ -1995,6 +1979,23 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P
}
break;
}
+ case PROP_POINTER:
+ {
+ StructRNA *prop_type;
+ BPy_StructRNA *param = (BPy_StructRNA *) value;
+
+ prop_type = RNA_property_pointer_type(ptr, prop);
+
+ if (value == Py_None)
+ RNA_property_pointer_set_index(ptr, prop, index, PointerRNA_NULL);
+ else if (RNA_struct_is_a(param->ptr.type, prop_type))
+ RNA_property_pointer_set_index(ptr, prop, index, param->ptr);
+ else {
+ PyErr_Format(PyExc_AttributeError, "expected an %.200s type", RNA_struct_ui_name(prop_type));
+ ret = -1;
+ }
+ break;
+ }
default:
PyErr_SetString(PyExc_AttributeError, "not an array type");
ret = -1;
@@ -6413,7 +6414,7 @@ PyObject *pyrna_id_CreatePyObject(ID *id)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
{
- if (BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *)obj)->ptr.type))) {
+ if (pyrna_id_CheckPyObject(obj)) {
*id = ((BPy_StructRNA *)obj)->ptr.id.data;
return true;
}
@@ -6423,6 +6424,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
}
}
+bool pyrna_id_CheckPyObject(PyObject *obj)
+{
+ return BPy_StructRNA_Check(obj) && (RNA_struct_is_ID(((BPy_StructRNA *) obj)->ptr.type));
+}
+
void BPY_rna_init(void)
{
#ifdef USE_MATHUTILS /* register mathutils callbacks, ok to run more than once. */
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f546c29..baa79a3 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -179,6 +179,7 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop);
/* extern'd by other modules which don't deal closely with RNA */
PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
+bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix);
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index bb40a21..3a978df 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -47,7 +47,7 @@
#define MAX_ARRAY_DIMENSION 10
typedef void (*ItemConvertFunc)(PyObject *, char *);
-typedef int (*ItemTypeCheckFunc)(PyObject *);
+typedef int (*ItemTypeCheckFunc)(PyObject *, StructRNA *);
typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
@@ -66,7 +66,7 @@ typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *)
/* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
/* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
-static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic,
+static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic, StructRNA *type,
ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
{
Py_ssize_t i;
@@ -110,7 +110,7 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[]
error_prefix, dim + 1, dimsize[dim + 1], item_seq_size);
ok = 0;
}
- else if (validate_array_type(item, dim + 1, totdim, dimsize, is_dynamic,
+ else if (validate_array_type(item, dim + 1, totdim, dimsize, is_dynamic, type,
check_item_type, item_type_str, error_prefix) == -1)
{
ok = 0;
@@ -145,7 +145,7 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[]
error_prefix, Py_TYPE(seq)->tp_name, i);
return -1;
}
- else if (!check_item_type(item)) {
+ else if (!check_item_type(item,type)) {
Py_DECREF(item);
/* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
@@ -318,7 +318,7 @@ static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
{
const int prop_flag = RNA_property_flag(prop);
- if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, (prop_flag & PROP_DYNAMIC) != 0,
+ if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, (prop_flag & PROP_DYNAMIC) != 0, RNA_property_pointer_type(ptr, prop),
check_item_type, item_type_str, error_prefix) == -1)
{
return -1;
@@ -492,7 +492,7 @@ static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
index += arrayoffset;
if (lvalue_dim == totdim) { /* single item, assign directly */
- if (!check_item_type(py)) {
+ if (!check_item_type(py, RNA_property_pointer_type(ptr, prop))) {
PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s",
error_prefix, RNA_struct_identifier(ptr->type),
RNA_property_identifier(prop), item_type_str,
@@ -528,23 +528,35 @@ static void py_to_bool(PyObject *py, char *data)
*(int *)data = (int)PyObject_IsTrue(py);
}
-static int py_float_check(PyObject *py)
+static void py_to_id_ptr(PyObject *py, char *data)
+{
+ struct ID* id;
+ pyrna_id_FromPyObject(py, &id);
+ RNA_id_pointer_create(id, (PointerRNA *)data);
+}
+
+static int py_float_check(PyObject *py, StructRNA *UNUSED(type))
{
/* accept both floats and integers */
return PyNumber_Check(py);
}
-static int py_int_check(PyObject *py)
+static int py_int_check(PyObject *py, StructRNA *UNUSED(type))
{
/* accept only integers */
return PyLong_Check(py);
}
-static int py_bool_check(PyObject *py)
+static int py_bool_check(PyObject *py, StructRNA *UNUSED(type))
{
return PyBool_Check(py);
}
+static int py_id_check(PyObject *py, StructRNA *type)
+{
+ return py == Py_None || (BPy_StructRNA_Check(py) && RNA_struct_is_a(((BPy_StructRNA *) py)->ptr.type, type));
+}
+
static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
{
RNA_property_float_set_index(ptr, prop, index, *(float *)value);
@@ -577,6 +589,14 @@ int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data,
ret = py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int),
py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
break;
+ case PROP_POINTER:
+ {
+ StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop);
+
+ ret = py_to_array(py, ptr, prop, param_data, py_id_check, RNA_struct_identifier(ptr_type), sizeof(PointerRNA),
+ py_to_id_ptr, (RNA_SetArrayFunc) RNA_property_pointer_set_array, error_prefix);
+ break;
+ }
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
ret = -1;
@@ -626,6 +646,12 @@ PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
case PROP_INT:
item = PyLong_FromLong(RNA_property_int_get_index(ptr, prop, index));
break;
+ case PROP_POINTER:
+ {
+ PointerRNA inner_ptr = RNA_property_pointer_get_index(ptr, prop, index);
+ item = pyrna_struct_CreatePyObject(&inner_ptr);
+ break;
+ }
default:
PyErr_SetString(PyExc_TypeError, "not an array type");
item = NULL;

Event Timeline