diff options
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_idprop.h | 27 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/idprop.c | 336 |
2 files changed, 363 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index a5cb6489194..c28ac63388b 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -32,6 +32,7 @@ struct BlendLibReader; struct BlendWriter; struct ID; struct IDProperty; +struct IDPropertyUIData; typedef union IDPropertyTemplate { int i; @@ -183,6 +184,10 @@ void IDP_Reset(struct IDProperty *prop, const struct IDProperty *reference); # define IDP_Id(prop) ((ID *)(prop)->data.pointer) #endif +int IDP_coerce_to_int_or_zero(const struct IDProperty *prop); +float IDP_coerce_to_float_or_zero(const struct IDProperty *prop); +double IDP_coerce_to_double_or_zero(const struct IDProperty *prop); + /** * Call a callback for each idproperty in the hierarchy under given root one (included). * @@ -209,6 +214,28 @@ void IDP_BlendReadData_impl(struct BlendDataReader *reader, void IDP_BlendReadLib(struct BlendLibReader *reader, struct IDProperty *prop); void IDP_BlendReadExpand(struct BlendExpander *expander, struct IDProperty *prop); +typedef enum eIDPropertyUIDataType { + /** Other properties types that don't support RNA UI data. */ + IDP_UI_DATA_TYPE_UNSUPPORTED = -1, + /** IDP_INT or IDP_ARRAY with subtype IDP_INT. */ + IDP_UI_DATA_TYPE_INT = 0, + /** IDP_FLOAT and IDP_DOUBLE or IDP_ARRAY properties with a float or double subtypes. */ + IDP_UI_DATA_TYPE_FLOAT = 1, + /** IDP_STRING properties. */ + IDP_UI_DATA_TYPE_STRING = 2, + /** IDP_ID. */ + IDP_UI_DATA_TYPE_ID = 3, +} eIDPropertyUIDataType; + +bool IDP_ui_data_supported(const struct IDProperty *prop); +eIDPropertyUIDataType IDP_ui_data_type(const struct IDProperty *prop); +void IDP_ui_data_free(struct IDProperty *prop); +void IDP_ui_data_free_unique_contents(struct IDPropertyUIData *ui_data, + eIDPropertyUIDataType type, + const struct IDPropertyUIData *other); +struct IDPropertyUIData *IDP_ui_data_ensure(struct IDProperty *prop); +struct IDPropertyUIData *IDP_ui_data_copy(const struct IDProperty *prop); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 7a88a00c44f..786df14756a 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -21,6 +21,7 @@ * \ingroup bke */ +#include <limits.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -274,6 +275,43 @@ void IDP_FreeArray(IDProperty *prop) } } +IDPropertyUIData *IDP_ui_data_copy(const IDProperty *prop) +{ + IDPropertyUIData *dst_ui_data = MEM_dupallocN(prop->ui_data); + + /* Copy extra type specific data. */ + switch (IDP_ui_data_type(prop)) { + case IDP_UI_DATA_TYPE_STRING: { + const IDPropertyUIDataString *src = (const IDPropertyUIDataString *)prop->ui_data; + IDPropertyUIDataString *dst = (IDPropertyUIDataString *)dst_ui_data; + dst->default_value = MEM_dupallocN(src->default_value); + break; + } + case IDP_UI_DATA_TYPE_ID: { + break; + } + case IDP_UI_DATA_TYPE_INT: { + const IDPropertyUIDataInt *src = (const IDPropertyUIDataInt *)prop->ui_data; + IDPropertyUIDataInt *dst = (IDPropertyUIDataInt *)dst_ui_data; + dst->default_array = MEM_dupallocN(src->default_array); + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + const IDPropertyUIDataFloat *src = (const IDPropertyUIDataFloat *)prop->ui_data; + IDPropertyUIDataFloat *dst = (IDPropertyUIDataFloat *)dst_ui_data; + dst->default_array = MEM_dupallocN(src->default_array); + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + break; + } + } + + dst_ui_data->description = MEM_dupallocN(prop->ui_data->description); + + return dst_ui_data; +} + static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(flag)) { IDProperty *newp = MEM_callocN(sizeof(IDProperty), __func__); @@ -284,6 +322,10 @@ static IDProperty *idp_generic_copy(const IDProperty *prop, const int UNUSED(fla newp->data.val = prop->data.val; newp->data.val2 = prop->data.val2; + if (prop->ui_data != NULL) { + newp->ui_data = IDP_ui_data_copy(prop); + } + return newp; } @@ -679,6 +721,7 @@ bool IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew void IDP_RemoveFromGroup(IDProperty *group, IDProperty *prop) { BLI_assert(group->type == IDP_GROUP); + BLI_assert(BLI_findindex(&group->data.group, prop) != -1); group->len--; BLI_remlink(&group->data.group, prop); @@ -725,6 +768,60 @@ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) /** \name Main Functions (IDProperty Main API) * \{ */ +/** + * Return an int from an IDProperty with a compatible type. This should be avoided, but + * it's sometimes necessary, for example when legacy files have incorrect property types. + */ +int IDP_coerce_to_int_or_zero(const IDProperty *prop) +{ + switch (prop->type) { + case IDP_INT: + return IDP_Int(prop); + case IDP_DOUBLE: + return (int)IDP_Double(prop); + case IDP_FLOAT: + return (int)IDP_Float(prop); + default: + return 0; + } +} + +/** + * Return a double from an IDProperty with a compatible type. This should be avoided, but + * it's sometimes necessary, for example when legacy files have incorrect property types. + */ +double IDP_coerce_to_double_or_zero(const IDProperty *prop) +{ + switch (prop->type) { + case IDP_DOUBLE: + return IDP_Double(prop); + case IDP_FLOAT: + return (double)IDP_Float(prop); + case IDP_INT: + return (double)IDP_Int(prop); + default: + return 0.0; + } +} + +/** + * Return a float from an IDProperty with a compatible type. This should be avoided, but + * it's sometimes necessary, for example when legacy files have incorrect property types. + */ +float IDP_coerce_to_float_or_zero(const IDProperty *prop) +{ + switch (prop->type) { + case IDP_FLOAT: + return IDP_Float(prop); + case IDP_DOUBLE: + return (float)IDP_Double(prop); + case IDP_INT: + return (float)IDP_Int(prop); + default: + return 0.0f; + } +} + IDProperty *IDP_CopyProperty_ex(const IDProperty *prop, const int flag) { switch (prop->type) { @@ -1000,6 +1097,85 @@ IDProperty *IDP_New(const char type, const IDPropertyTemplate *val, const char * } /** + * Free allocated pointers in the UI data that isn't shared with the UI data in the #other + * argument. Useful for returning early on failure when updating UI data in place, or when + * replacing a subset of the UI data's allocated pointers. + */ +void IDP_ui_data_free_unique_contents(IDPropertyUIData *ui_data, + const eIDPropertyUIDataType type, + const IDPropertyUIData *other) +{ + if (ui_data->description != other->description) { + MEM_SAFE_FREE(ui_data->description); + } + + switch (type) { + case IDP_UI_DATA_TYPE_STRING: { + const IDPropertyUIDataString *other_string = (const IDPropertyUIDataString *)other; + IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data; + if (ui_data_string->default_value != other_string->default_value) { + MEM_SAFE_FREE(ui_data_string->default_value); + } + break; + } + case IDP_UI_DATA_TYPE_ID: { + break; + } + case IDP_UI_DATA_TYPE_INT: { + const IDPropertyUIDataInt *other_int = (const IDPropertyUIDataInt *)other; + IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data; + if (ui_data_int->default_array != other_int->default_array) { + MEM_SAFE_FREE(ui_data_int->default_array); + } + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + const IDPropertyUIDataFloat *other_float = (const IDPropertyUIDataFloat *)other; + IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data; + if (ui_data_float->default_array != other_float->default_array) { + MEM_SAFE_FREE(ui_data_float->default_array); + } + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + break; + } + } +} + +void IDP_ui_data_free(IDProperty *prop) +{ + switch (IDP_ui_data_type(prop)) { + case IDP_UI_DATA_TYPE_STRING: { + IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data; + MEM_SAFE_FREE(ui_data_string->default_value); + break; + } + case IDP_UI_DATA_TYPE_ID: { + break; + } + case IDP_UI_DATA_TYPE_INT: { + IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data; + MEM_SAFE_FREE(ui_data_int->default_array); + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data; + MEM_SAFE_FREE(ui_data_float->default_array); + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + break; + } + } + + MEM_SAFE_FREE(prop->ui_data->description); + + MEM_freeN(prop->ui_data); + prop->ui_data = NULL; +} + +/** * \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. */ @@ -1024,6 +1200,10 @@ void IDP_FreePropertyContent_ex(IDProperty *prop, const bool do_id_user) } break; } + + if (prop->ui_data != NULL) { + IDP_ui_data_free(prop); + } } void IDP_FreePropertyContent(IDProperty *prop) @@ -1104,6 +1284,48 @@ void IDP_foreach_property(IDProperty *id_property_root, void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer); +static void write_ui_data(const IDProperty *prop, BlendWriter *writer) +{ + IDPropertyUIData *ui_data = prop->ui_data; + + BLO_write_string(writer, ui_data->description); + + switch (IDP_ui_data_type(prop)) { + case IDP_UI_DATA_TYPE_STRING: { + IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)ui_data; + BLO_write_string(writer, ui_data_string->default_value); + BLO_write_struct(writer, IDPropertyUIDataString, ui_data); + break; + } + case IDP_UI_DATA_TYPE_ID: { + BLO_write_struct(writer, IDPropertyUIDataID, ui_data); + break; + } + case IDP_UI_DATA_TYPE_INT: { + IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)ui_data; + if (prop->type == IDP_ARRAY) { + BLO_write_int32_array( + writer, (uint)ui_data_int->default_array_len, (int32_t *)ui_data_int->default_array); + } + BLO_write_struct(writer, IDPropertyUIDataInt, ui_data); + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)ui_data; + if (prop->type == IDP_ARRAY) { + BLO_write_double_array( + writer, (uint)ui_data_float->default_array_len, ui_data_float->default_array); + } + BLO_write_struct(writer, IDPropertyUIDataFloat, ui_data); + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + BLI_assert_unreachable(); + break; + } + } +} + static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer) { /* Remember to set #IDProperty.totallen to len in the linking code! */ @@ -1165,6 +1387,9 @@ void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer) IDP_WriteIDPArray(prop, writer); break; } + if (prop->ui_data != NULL) { + write_ui_data(prop, writer); + } } void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop) @@ -1175,6 +1400,43 @@ void IDP_BlendWrite(BlendWriter *writer, const IDProperty *prop) static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); +static void read_ui_data(IDProperty *prop, BlendDataReader *reader) +{ + BLO_read_data_address(reader, &prop->ui_data); + BLO_read_data_address(reader, &prop->ui_data->description); + + switch (IDP_ui_data_type(prop)) { + case IDP_UI_DATA_TYPE_STRING: { + IDPropertyUIDataString *ui_data_string = (IDPropertyUIDataString *)prop->ui_data; + BLO_read_data_address(reader, &ui_data_string->default_value); + break; + } + case IDP_UI_DATA_TYPE_ID: { + break; + } + case IDP_UI_DATA_TYPE_INT: { + IDPropertyUIDataInt *ui_data_int = (IDPropertyUIDataInt *)prop->ui_data; + if (prop->type == IDP_ARRAY) { + BLO_read_int32_array( + reader, ui_data_int->default_array_len, (int **)&ui_data_int->default_array); + } + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + IDPropertyUIDataFloat *ui_data_float = (IDPropertyUIDataFloat *)prop->ui_data; + if (prop->type == IDP_ARRAY) { + BLO_read_double_array( + reader, ui_data_float->default_array_len, (double **)&ui_data_float->default_array); + } + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + BLI_assert_unreachable(); + break; + } + } +} + static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) { /* since we didn't save the extra buffer, set totallen to len */ @@ -1279,6 +1541,10 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader) prop->subtype = 0; IDP_Int(prop) = 0; } + + if (prop->ui_data != NULL) { + read_ui_data(prop, reader); + } } void IDP_BlendReadData_impl(BlendDataReader *reader, IDProperty **prop, const char *caller_func_id) @@ -1358,4 +1624,74 @@ void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop) } } +eIDPropertyUIDataType IDP_ui_data_type(const IDProperty *prop) +{ + if (prop->type == IDP_STRING) { + return IDP_UI_DATA_TYPE_STRING; + } + if (prop->type == IDP_ID) { + return IDP_UI_DATA_TYPE_ID; + } + if (prop->type == IDP_INT || (prop->type == IDP_ARRAY && prop->subtype == IDP_INT)) { + return IDP_UI_DATA_TYPE_INT; + } + if (ELEM(prop->type, IDP_FLOAT, IDP_DOUBLE) || + (prop->type == IDP_ARRAY && ELEM(prop->subtype, IDP_FLOAT, IDP_DOUBLE))) { + return IDP_UI_DATA_TYPE_FLOAT; + } + return IDP_UI_DATA_TYPE_UNSUPPORTED; +} + +bool IDP_ui_data_supported(const IDProperty *prop) +{ + return IDP_ui_data_type(prop) != IDP_UI_DATA_TYPE_UNSUPPORTED; +} + +IDPropertyUIData *IDP_ui_data_ensure(IDProperty *prop) +{ + if (prop->ui_data != NULL) { + return prop->ui_data; + } + + switch (IDP_ui_data_type(prop)) { + case IDP_UI_DATA_TYPE_STRING: { + prop->ui_data = MEM_callocN(sizeof(IDPropertyUIDataString), __func__); + break; + } + case IDP_UI_DATA_TYPE_ID: { + IDPropertyUIDataID *ui_data = MEM_callocN(sizeof(IDPropertyUIDataID), __func__); + prop->ui_data = (IDPropertyUIData *)ui_data; + break; + } + case IDP_UI_DATA_TYPE_INT: { + IDPropertyUIDataInt *ui_data = MEM_callocN(sizeof(IDPropertyUIDataInt), __func__); + ui_data->min = -INT_MAX; + ui_data->max = INT_MAX; + ui_data->soft_min = -INT_MAX; + ui_data->soft_max = INT_MAX; + ui_data->step = 1; + prop->ui_data = (IDPropertyUIData *)ui_data; + break; + } + case IDP_UI_DATA_TYPE_FLOAT: { + IDPropertyUIDataFloat *ui_data = MEM_callocN(sizeof(IDPropertyUIDataFloat), __func__); + ui_data->min = -FLT_MAX; + ui_data->max = FLT_MAX; + ui_data->soft_min = -FLT_MAX; + ui_data->soft_max = FLT_MAX; + ui_data->step = 1.0f; + ui_data->precision = 3; + prop->ui_data = (IDPropertyUIData *)ui_data; + break; + } + case IDP_UI_DATA_TYPE_UNSUPPORTED: { + /* UI data not supported for remaining types, this shouldn't be called in those cases. */ + BLI_assert_unreachable(); + break; + } + } + + return prop->ui_data; +} + /** \} */ |