From a7b3047cefcbfae4d8b13e15026497fd5ae92730 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Thu, 13 Apr 2017 12:30:03 +0300 Subject: Datablock ID Properties The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the [[http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.67/Python_Nodes|Python Nodes release notes]]. So this patch allows Python scripts to create ID Properties which reference datablocks. This functionality is implemented for `PointerProperty` and now such properties can be created with Python. In addition to the standard update callback, `PointerProperty` can have a `poll` callback (standard RNA) which is useful for search menus. For details see the test included in this patch. Original author: @artfunkel Alexander (Blend4Web Team) Reviewers: brecht, artfunkel, mont29, campbellbarton Reviewed By: mont29, campbellbarton Subscribers: jta, sergey, campbellbarton, wisaac, poseidon4o, mont29, homyachetser, Evgeny_Rodygin, AlexKowel, yurikovelenov, fjuhec, sharlybg, cardboard, duarteframos, blueprintrandom, a.romanov, BYOB, disnel, aditiapratama, bliblubli, dfelinto, lukastoenne Maniphest Tasks: T37754 Differential Revision: https://developer.blender.org/D113 --- source/blender/blenkernel/intern/idprop.c | 117 +++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 35 deletions(-) (limited to 'source/blender/blenkernel/intern/idprop.c') diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 5e4e8eb34ad..074a9a12fe0 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -117,14 +117,14 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array) return narray; } -void IDP_FreeIDPArray(IDProperty *prop) +static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) { int i; BLI_assert(prop->type == IDP_IDPARRAY); for (i = 0; i < prop->len; i++) - IDP_FreeProperty(GETPROP(prop, i)); + IDP_FreeProperty_ex(GETPROP(prop, i), do_id_user); if (prop->data.pointer) MEM_freeN(prop->data.pointer); @@ -437,22 +437,24 @@ void IDP_FreeString(IDProperty *prop) /* -------------------------------------------------------------------- */ -/* ID Type (not in use yet) */ +/* ID Type */ -/** \name IDProperty ID API (unused) +/** \name IDProperty ID API * \{ */ -void IDP_LinkID(IDProperty *prop, ID *id) -{ - if (prop->data.pointer) - id_us_min(((ID *)prop->data.pointer)); - prop->data.pointer = id; - id_us_plus(id); -} -void IDP_UnlinkID(IDProperty *prop) +static IDProperty *IDP_CopyID(const IDProperty *prop) { - id_us_min(((ID *)prop->data.pointer)); + IDProperty *newp; + + BLI_assert(prop->type == IDP_ID); + newp = idp_generic_copy(prop); + + newp->data.pointer = prop->data.pointer; + id_us_plus(IDP_Id(newp)); + + return newp; } + /** \} */ @@ -710,13 +712,13 @@ IDProperty *IDP_GetPropertyTypeFromGroup(IDProperty *prop, const char *name, con * This is because all ID Property freeing functions free only direct data (not the ID Property * struct itself), but for Groups the child properties *are* considered * direct data. */ -static void IDP_FreeGroup(IDProperty *prop) +static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) { IDProperty *loop; BLI_assert(prop->type == IDP_GROUP); for (loop = prop->data.group.first; loop; loop = loop->next) { - IDP_FreeProperty(loop); + IDP_FreeProperty_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); } @@ -733,12 +735,51 @@ IDProperty *IDP_CopyProperty(const 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 */ +/* TODO Nuke this once its only user has been correctly converted to use generic ID management from BKE_library! */ +void IDP_RelinkProperty(struct IDProperty *prop) +{ + if (!prop) + return; + + switch (prop->type) { + case IDP_GROUP: + { + for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) { + IDP_RelinkProperty(loop); + } + break; + } + case IDP_IDPARRAY: + { + IDProperty *idp_array = IDP_Array(prop); + for (int i = 0; i < prop->len; i++) { + IDP_RelinkProperty(&idp_array[i]); + } + break; + } + case IDP_ID: + { + ID *id = IDP_Id(prop); + if (id && id->newid) { + id_us_min(IDP_Id(prop)); + prop->data.pointer = id->newid; + id_us_plus(IDP_Id(prop)); + } + break; + } + default: + break; /* Nothing to do for other IDProp types. */ + } +} + /** * 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 @@ -835,6 +876,8 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is return false; return true; } + case IDP_ID: + return (IDP_Id(prop1) == IDP_Id(prop2)); default: /* should never get here */ BLI_assert(0); @@ -910,6 +953,7 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * prop->len = prop->totallen = val->array.len; break; } + printf("%s: bad array type.\n",__func__); return NULL; } case IDP_STRING: @@ -956,6 +1000,14 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * /* heh I think all needed values are set properly by calloc anyway :) */ break; } + case IDP_ID: + { + prop = MEM_callocN(sizeof(IDProperty), "IDProperty datablock"); + prop->data.pointer = (void *)val->id; + prop->type = IDP_ID; + id_us_plus(IDP_Id(prop)); + break; + } default: { prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); @@ -970,11 +1022,10 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * } /** - * \note this will free all child properties of list arrays and groups! - * Also, note that this does NOT unlink anything! Plus it doesn't free - * the actual struct IDProperty struct either. + * \note This will free allocated data, all child properties of arrays and groups, and unlink IDs! + * But it does not free the actual IDProperty struct itself. */ -void IDP_FreeProperty(IDProperty *prop) +void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user) { switch (prop->type) { case IDP_ARRAY: @@ -984,14 +1035,24 @@ void IDP_FreeProperty(IDProperty *prop) IDP_FreeString(prop); break; case IDP_GROUP: - IDP_FreeGroup(prop); + IDP_FreeGroup(prop, do_id_user); break; case IDP_IDPARRAY: - IDP_FreeIDPArray(prop); + IDP_FreeIDPArray(prop, do_id_user); + break; + case IDP_ID: + if (do_id_user) { + id_us_min(IDP_Id(prop)); + } break; } } +void IDP_FreeProperty(IDProperty *prop) +{ + IDP_FreeProperty_ex(prop, true); +} + void IDP_ClearProperty(IDProperty *prop) { IDP_FreeProperty(prop); @@ -999,18 +1060,4 @@ void IDP_ClearProperty(IDProperty *prop) prop->len = prop->totallen = 0; } -/** - * Unlinks any struct IDProperty<->ID linkage that might be going on. - * - * \note currently unused - */ -void IDP_UnlinkProperty(IDProperty *prop) -{ - switch (prop->type) { - case IDP_ID: - IDP_UnlinkID(prop); - break; - } -} - /** \} */ -- cgit v1.2.3