Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_idprop.h27
-rw-r--r--source/blender/blenkernel/intern/idprop.c336
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;
+}
+
/** \} */