BPY: Implement get_transform and set_transform for runtime-defined RNA properties.

Improve handling of runtime defined python RNA properties. Mainly:
* Add `get_transform` and `set_transform` new callbacks.
  These allow to edit the value, while still using the default
  (IDProperty-based) storage system.
* Read-only properties should now be defined using a new `options` flag,
  `READ_ONLY`.
* `get`/`set` should only be used when storing data outside of the
  default system now.
  * Having a `get` without a `set` defined forces property to be
    read-only (same behavior as before).
  * Having a `set` without a `get` is now an error.
* Just like with existing `get/set` callbacks, `get_/set_transform`
  callbacks must always generate values matching the constraints defined
  by their `bpy.props` property definition (same type, within required
  range, same dimensions/sizes for the `Vector` properties, etc.).
* To simplify handling of non-statically sized strings, the relevant
  RNA API has been modified, to use `std::string` instead of
  (allocated) char arrays.

Relevant unittests and benchmarking have been added or updated as part
of this project.

Note: From initial benchmarking, 'transform' versions of get/set are
several times faster than 'real' get/set.

Implements #141042.

Pull Request: https://projects.blender.org/blender/blender/pulls/141303
This commit is contained in:
Bastien Montagne
2025-09-02 11:30:09 +02:00
committed by Bastien Montagne
parent 75c66158aa
commit 469f54f484
19 changed files with 2762 additions and 740 deletions

View File

@@ -280,6 +280,8 @@ static void GIZMO_GT_primitive_3d(wmGizmoType *gzt)
RNA_def_property_enum_funcs_runtime(prop,
gizmo_primitive_rna__draw_style_get_fn,
gizmo_primitive_rna__draw_style_set_fn,
nullptr,
nullptr,
nullptr);
prop = RNA_def_float_factor(
@@ -287,11 +289,16 @@ static void GIZMO_GT_primitive_3d(wmGizmoType *gzt)
RNA_def_property_float_funcs_runtime(prop,
gizmo_primitive_rna__arc_inner_factor_get_fn,
gizmo_primitive_rna__arc_inner_factor_set_fn,
nullptr,
nullptr,
nullptr);
prop = RNA_def_boolean(gzt->srna, "draw_inner", true, "Draw Inner", "");
RNA_def_property_boolean_funcs_runtime(
prop, gizmo_primitive_rna__draw_inner_get_fn, gizmo_primitive_rna__draw_inner_set_fn);
RNA_def_property_boolean_funcs_runtime(prop,
gizmo_primitive_rna__draw_inner_get_fn,
gizmo_primitive_rna__draw_inner_set_fn,
nullptr,
nullptr);
}
void ED_gizmotypes_primitive_3d()

View File

@@ -339,8 +339,12 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Point that defines the location of the perpendicular snap",
FLT_MIN,
FLT_MAX);
RNA_def_property_float_array_funcs_runtime(
prop, gizmo_snap_rna_prevpoint_get_fn, gizmo_snap_rna_prevpoint_set_fn, nullptr);
RNA_def_property_float_array_funcs_runtime(prop,
gizmo_snap_rna_prevpoint_get_fn,
gizmo_snap_rna_prevpoint_set_fn,
nullptr,
nullptr,
nullptr);
/* Returns. */
prop = RNA_def_float_translation(gzt->srna,
@@ -353,8 +357,12 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Snap Point Location",
FLT_MIN,
FLT_MAX);
RNA_def_property_float_array_funcs_runtime(
prop, gizmo_snap_rna_location_get_fn, gizmo_snap_rna_location_set_fn, nullptr);
RNA_def_property_float_array_funcs_runtime(prop,
gizmo_snap_rna_location_get_fn,
gizmo_snap_rna_location_set_fn,
nullptr,
nullptr,
nullptr);
prop = RNA_def_float_vector_xyz(gzt->srna,
"normal",
@@ -366,7 +374,8 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
"Snap Point Normal",
FLT_MIN,
FLT_MAX);
RNA_def_property_float_array_funcs_runtime(prop, gizmo_snap_rna_normal_get_fn, nullptr, nullptr);
RNA_def_property_float_array_funcs_runtime(
prop, gizmo_snap_rna_normal_get_fn, nullptr, nullptr, nullptr, nullptr);
prop = RNA_def_int_vector(gzt->srna,
"snap_elem_index",
@@ -379,7 +388,7 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
INT_MIN,
INT_MAX);
RNA_def_property_int_array_funcs_runtime(
prop, gizmo_snap_rna_snap_elem_index_get_fn, nullptr, nullptr);
prop, gizmo_snap_rna_snap_elem_index_get_fn, nullptr, nullptr, nullptr, nullptr);
prop = RNA_def_enum(gzt->srna,
"snap_source_type",
@@ -390,6 +399,8 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
RNA_def_property_enum_funcs_runtime(prop,
gizmo_snap_rna_snap_srouce_type_get_fn,
gizmo_snap_rna_snap_srouce_type_set_fn,
nullptr,
nullptr,
nullptr);
}

View File

@@ -783,7 +783,8 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
DT_LAYERS_ACTIVE_SRC,
"Source Layers Selection",
"Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_layers_select_itemf);
RNA_def_property_enum_funcs_runtime(
prop, nullptr, nullptr, dt_layers_select_itemf, nullptr, nullptr);
prop = RNA_def_enum(ot->srna,
"layers_select_dst",
@@ -791,7 +792,8 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
DT_LAYERS_ACTIVE_DST,
"Destination Layers Matching",
"How to match source and destination layers");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_layers_select_itemf);
RNA_def_property_enum_funcs_runtime(
prop, nullptr, nullptr, dt_layers_select_itemf, nullptr, nullptr);
prop = RNA_def_enum(ot->srna,
"mix_mode",
@@ -799,7 +801,7 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
CDT_MIX_TRANSFER,
"Mix Mode",
"How to affect destination elements with source values");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_mix_mode_itemf);
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_mix_mode_itemf, nullptr, nullptr);
RNA_def_float(
ot->srna,
"mix_factor",
@@ -948,7 +950,8 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot)
DT_LAYERS_ACTIVE_SRC,
"Source Layers Selection",
"Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_layers_select_src_itemf);
RNA_def_property_enum_funcs_runtime(
prop, nullptr, nullptr, dt_layers_select_src_itemf, nullptr, nullptr);
prop = RNA_def_enum(ot->srna,
"layers_select_dst",
@@ -956,7 +959,8 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot)
DT_LAYERS_ACTIVE_DST,
"Destination Layers Matching",
"How to match source and destination layers");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, dt_layers_select_dst_itemf);
RNA_def_property_enum_funcs_runtime(
prop, nullptr, nullptr, dt_layers_select_dst_itemf, nullptr, nullptr);
}
} // namespace blender::ed::object

View File

@@ -762,7 +762,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(
ot->srna, "old_id", rna_enum_dummy_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf, nullptr, nullptr);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
ot->prop = RNA_def_enum(ot->srna,
@@ -771,7 +771,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
0,
"New ID",
"New ID to remap all selected IDs' users to");
RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_enum_funcs_runtime(
ot->prop, nullptr, nullptr, outliner_id_itemf, nullptr, nullptr);
RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}

View File

@@ -541,7 +541,8 @@ std::optional<std::string> RNA_property_string_path_filter(const bContext *C,
PropertyRNA *prop);
/**
* \return the length without `\0` terminator.
* \return The final length without `\0` terminator (might differ from the length of the stored
* string, when a `get_transform` callback is defined).
*/
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_string_get_default(PropertyRNA *prop, char *value, int value_maxncpy);

View File

@@ -573,36 +573,64 @@ void RNA_def_property_enum_default_func(PropertyRNA *prop, const char *get_defau
void RNA_def_property_srna(PropertyRNA *prop, const char *type);
void RNA_def_py_data(PropertyRNA *prop, void *py_data);
/* API to define callbacks for runtime-defined properties (mainly for Operators, and from the
* Python `bpy.props` API).
*
* These expect 'extended' versions of the callbacks, with both the StructRNA owner and the
* PropertyRNA as first arguments.
*
* The 'Transform' ones allow to add a transform step (applied after getting, or before setting the
* value), which only modifies the value, but does not handle actual storage. Currently only used
* by `bpy`, more details in the documentation of #BPyPropStore.
*/
void RNA_def_property_boolean_funcs_runtime(PropertyRNA *prop,
BooleanPropertyGetFunc getfunc,
BooleanPropertySetFunc setfunc);
void RNA_def_property_boolean_array_funcs_runtime(PropertyRNA *prop,
BooleanArrayPropertyGetFunc getfunc,
BooleanArrayPropertySetFunc setfunc);
BooleanPropertySetFunc setfunc,
BooleanPropertyGetTransformFunc get_transform_fn,
BooleanPropertySetTransformFunc set_transform_fn);
void RNA_def_property_boolean_array_funcs_runtime(
PropertyRNA *prop,
BooleanArrayPropertyGetFunc getfunc,
BooleanArrayPropertySetFunc setfunc,
BooleanArrayPropertyGetTransformFunc get_transform_fn,
BooleanArrayPropertySetTransformFunc set_transform_fn);
void RNA_def_property_int_funcs_runtime(PropertyRNA *prop,
IntPropertyGetFunc getfunc,
IntPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc);
IntPropertyRangeFunc rangefunc,
IntPropertyGetTransformFunc get_transform_fn,
IntPropertySetTransformFunc set_transform_fn);
void RNA_def_property_int_array_funcs_runtime(PropertyRNA *prop,
IntArrayPropertyGetFunc getfunc,
IntArrayPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc);
IntPropertyRangeFunc rangefunc,
IntArrayPropertyGetTransformFunc get_transform_fn,
IntArrayPropertySetTransformFunc set_transform_fn);
void RNA_def_property_float_funcs_runtime(PropertyRNA *prop,
FloatPropertyGetFunc getfunc,
FloatPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc);
void RNA_def_property_float_array_funcs_runtime(PropertyRNA *prop,
FloatArrayPropertyGetFunc getfunc,
FloatArrayPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc);
FloatPropertyRangeFunc rangefunc,
FloatPropertyGetTransformFunc get_transform_fn,
FloatPropertySetTransformFunc set_transform_fn);
void RNA_def_property_float_array_funcs_runtime(
PropertyRNA *prop,
FloatArrayPropertyGetFunc getfunc,
FloatArrayPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc,
FloatArrayPropertyGetTransformFunc get_transform_fn,
FloatArrayPropertySetTransformFunc set_transform_fn);
void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
EnumPropertyGetFunc getfunc,
EnumPropertySetFunc setfunc,
EnumPropertyItemFunc itemfunc);
EnumPropertyItemFunc itemfunc,
EnumPropertyGetTransformFunc get_transform_fn,
EnumPropertySetTransformFunc set_transform_fn);
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc);
StringPropertySetFunc setfunc,
StringPropertyGetTransformFunc get_transform_fn,
StringPropertySetTransformFunc set_transform_fn);
void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,
StringPropertySearchFunc search_fn,
eStringPropertySearchFlag search_flag);

View File

@@ -684,30 +684,93 @@ struct EnumPropertyItem {
/** Separator for RNA enum that begins a new column in menus (shown in the UI). */
#define RNA_ENUM_ITEM_SEPR_COLUMN RNA_ENUM_ITEM_HEADING("", NULL)
/* extended versions with PropertyRNA argument */
/* Extended versions with PropertyRNA argument. Used in particular by the bpy code to wrap all the
* py-defined callbacks when defining a property using `bpy.props` module.
*
* The 'Transform' ones allow to add a transform step (applied after getting, or before setting the
* value), which only modifies the value, but does not handle actual storage. Currently only used
* by `bpy`, more details in the documentation of #BPyPropStore.
*/
using BooleanPropertyGetFunc = bool (*)(PointerRNA *ptr, PropertyRNA *prop);
using BooleanPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, bool value);
using BooleanArrayPropertyGetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, bool *values);
using BooleanPropertyGetTransformFunc = bool (*)(PointerRNA *ptr,
PropertyRNA *prop,
bool value,
bool is_set);
using BooleanPropertySetTransformFunc =
bool (*)(PointerRNA *ptr, PropertyRNA *prop, bool new_value, bool curr_value, bool is_set);
using BooleanArrayPropertyGetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, bool *r_values);
using BooleanArrayPropertySetFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const bool *values);
const bool *r_values);
using BooleanArrayPropertyGetTransformFunc = void (*)(
PointerRNA *ptr, PropertyRNA *prop, const bool *curr_values, bool is_set, bool *r_values);
using BooleanArrayPropertySetTransformFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const bool *new_values,
const bool *curr_values,
bool is_set,
bool *r_values);
using IntPropertyGetFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using IntPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int value);
using IntPropertyGetTransformFunc = int (*)(PointerRNA *ptr,
PropertyRNA *prop,
int value,
bool is_set);
using IntPropertySetTransformFunc =
int (*)(PointerRNA *ptr, PropertyRNA *prop, int new_value, int curr_value, bool is_set);
using IntArrayPropertyGetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int *values);
using IntArrayPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, const int *values);
using IntArrayPropertyGetTransformFunc = void (*)(
PointerRNA *ptr, PropertyRNA *prop, const int *curr_values, bool is_set, int *r_values);
using IntArrayPropertySetTransformFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const int *new_values,
const int *curr_values,
bool is_set,
int *r_values);
using IntPropertyRangeFunc =
void (*)(PointerRNA *ptr, PropertyRNA *prop, int *min, int *max, int *softmin, int *softmax);
using FloatPropertyGetFunc = float (*)(PointerRNA *ptr, PropertyRNA *prop);
using FloatPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, float value);
using FloatPropertyGetTransformFunc = float (*)(PointerRNA *ptr,
PropertyRNA *prop,
float value,
bool is_set);
using FloatPropertySetTransformFunc =
float (*)(PointerRNA *ptr, PropertyRNA *prop, float new_value, float curr_value, bool is_set);
using FloatArrayPropertyGetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, float *values);
using FloatArrayPropertySetFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const float *values);
using FloatArrayPropertyGetTransformFunc = void (*)(
PointerRNA *ptr, PropertyRNA *prop, const float *curr_values, bool is_set, float *r_values);
using FloatArrayPropertySetTransformFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const float *new_values,
const float *curr_values,
bool is_set,
float *r_values);
using FloatPropertyRangeFunc = void (*)(
PointerRNA *ptr, PropertyRNA *prop, float *min, float *max, float *softmin, float *softmax);
using StringPropertyGetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, char *value);
using StringPropertyGetFunc = std::string (*)(PointerRNA *ptr, PropertyRNA *prop);
using StringPropertyLengthFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using StringPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, const char *value);
using StringPropertySetFunc = void (*)(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &value);
using StringPropertyGetTransformFunc = std::string (*)(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &value,
bool is_set);
using StringPropertySetTransformFunc = std::string (*)(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &new_value,
const std::string &curr_value,
bool is_set);
struct StringPropertySearchVisitParams {
/** Text being searched for. */
@@ -763,6 +826,12 @@ using StringPropertyPathFilterFunc = std::optional<std::string> (*)(const bConte
using EnumPropertyGetFunc = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using EnumPropertySetFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int value);
using EnumPropertyGetTransformFunc = int (*)(PointerRNA *ptr,
PropertyRNA *prop,
int value,
bool is_set);
using EnumPropertySetTransformFunc =
int (*)(PointerRNA *ptr, PropertyRNA *prop, int new_value, int curr_value, bool is_set);
/* same as PropEnumItemFunc */
using EnumPropertyItemFunc = const EnumPropertyItem *(*)(bContext *C,
PointerRNA *ptr,

View File

@@ -2050,7 +2050,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
if (!(prop->flag & PROP_EDITABLE) &&
(bprop->set || bprop->set_ex || bprop->setarray || bprop->setarray_ex))
(bprop->set || bprop->set_ex || bprop->set_transform || bprop->setarray ||
bprop->setarray_ex || bprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is read-only but has defines a \"set\" callback.",
@@ -2060,7 +2061,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
}
if (!prop->arraydimension &&
(bprop->getarray || bprop->getarray_ex || bprop->setarray || bprop->setarray_ex))
(bprop->getarray || bprop->getarray_ex || bprop->getarray_transform || bprop->setarray ||
bprop->setarray_ex || bprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is not an array but defines an array callback.",
@@ -2091,7 +2093,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
if (!(prop->flag & PROP_EDITABLE) &&
(iprop->set || iprop->set_ex || iprop->setarray || iprop->setarray_ex))
(iprop->set || iprop->set_ex || iprop->set_transform || iprop->setarray ||
iprop->setarray_ex || iprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is read-only but has defines a \"set\" callback.",
@@ -2101,7 +2104,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
}
if (!prop->arraydimension &&
(iprop->getarray || iprop->getarray_ex || iprop->setarray || iprop->setarray_ex))
(iprop->getarray || iprop->getarray_ex || iprop->getarray_transform || iprop->setarray ||
iprop->setarray_ex || iprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is not an array but defines an array callback.",
@@ -2136,7 +2140,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
if (!(prop->flag & PROP_EDITABLE) &&
(fprop->set || fprop->set_ex || fprop->setarray || fprop->setarray_ex))
(fprop->set || fprop->set_ex || fprop->set_transform || fprop->setarray ||
fprop->setarray_ex || fprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is read-only but has defines a \"set\" callback.",
@@ -2146,7 +2151,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
}
if (!prop->arraydimension &&
(fprop->getarray || fprop->getarray_ex || fprop->setarray || fprop->setarray_ex))
(fprop->getarray || fprop->getarray_ex || fprop->getarray_transform || fprop->setarray ||
fprop->setarray_ex || fprop->setarray_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, is not an array but defines an array callback.",
@@ -2181,7 +2187,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (dp->enumbitflags && eprop->item_fn &&
!(eprop->item != rna_enum_dummy_NULL_items || eprop->set || eprop->set_ex))
!(eprop->item != rna_enum_dummy_NULL_items || eprop->set || eprop->set_ex ||
eprop->set_transform))
{
CLOG_ERROR(&LOG,
"%s.%s, bitflag enum should not define an `item` callback function, unless "
@@ -2191,7 +2198,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
DefRNA.error = true;
}
if (!(prop->flag & PROP_EDITABLE) && (eprop->set || eprop->set_ex)) {
if (!(prop->flag & PROP_EDITABLE) && (eprop->set || eprop->set_ex || eprop->set_transform)) {
CLOG_ERROR(&LOG,
"%s.%s, is read-only but has defines a \"set\" callback.",
srna->identifier,
@@ -2212,7 +2219,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
if (!(prop->flag & PROP_EDITABLE) && (sprop->set || sprop->set_ex)) {
if (!(prop->flag & PROP_EDITABLE) && (sprop->set || sprop->set_ex || sprop->set_transform)) {
CLOG_ERROR(&LOG,
"%s.%s, is read-only but has defines a \"set\" callback.",
srna->identifier,
@@ -4453,7 +4460,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_BOOLEAN: {
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, ",
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, ",
rna_function_string(bprop->get),
rna_function_string(bprop->set),
rna_function_string(bprop->getarray),
@@ -4462,6 +4469,10 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(bprop->set_ex),
rna_function_string(bprop->getarray_ex),
rna_function_string(bprop->setarray_ex),
rna_function_string(bprop->get_transform),
rna_function_string(bprop->set_transform),
rna_function_string(bprop->getarray_transform),
rna_function_string(bprop->setarray_transform),
rna_function_string(bprop->get_default),
rna_function_string(bprop->get_default_array),
bprop->defaultvalue);
@@ -4476,7 +4487,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_INT: {
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,\n\t",
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,\n\t",
rna_function_string(iprop->get),
rna_function_string(iprop->set),
rna_function_string(iprop->getarray),
@@ -4486,7 +4497,11 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(iprop->set_ex),
rna_function_string(iprop->getarray_ex),
rna_function_string(iprop->setarray_ex),
rna_function_string(iprop->range_ex));
rna_function_string(iprop->range_ex),
rna_function_string(iprop->get_transform),
rna_function_string(iprop->set_transform),
rna_function_string(iprop->getarray_transform),
rna_function_string(iprop->setarray_transform));
fprintf(f, "%s", rna_ui_scale_type_string(iprop->ui_scale_type));
fprintf(f, ", ");
rna_int_print(f, iprop->softmin);
@@ -4517,7 +4532,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_FLOAT: {
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, ",
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, ",
rna_function_string(fprop->get),
rna_function_string(fprop->set),
rna_function_string(fprop->getarray),
@@ -4527,7 +4542,11 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
rna_function_string(fprop->set_ex),
rna_function_string(fprop->getarray_ex),
rna_function_string(fprop->setarray_ex),
rna_function_string(fprop->range_ex));
rna_function_string(fprop->range_ex),
rna_function_string(fprop->get_transform),
rna_function_string(fprop->set_transform),
rna_function_string(fprop->getarray_transform),
rna_function_string(fprop->setarray_transform));
fprintf(f, "%s, ", rna_ui_scale_type_string(fprop->ui_scale_type));
rna_float_print(f, fprop->softmin);
fprintf(f, ", ");
@@ -4559,13 +4578,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_STRING: {
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, %s, eStringPropertySearchFlag(%d), %s, %d, ",
"\t%s, %s, %s, %s, %s, %s, %s, %s, %s, eStringPropertySearchFlag(%d), %s, %d, ",
rna_function_string(sprop->get),
rna_function_string(sprop->length),
rna_function_string(sprop->set),
rna_function_string(sprop->get_ex),
rna_function_string(sprop->length_ex),
rna_function_string(sprop->set_ex),
rna_function_string(sprop->get_transform),
rna_function_string(sprop->set_transform),
rna_function_string(sprop->search),
int(sprop->search_flag),
rna_function_string(sprop->path_filter),
@@ -4577,12 +4598,14 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
fprintf(f,
"\t%s, %s, %s, %s, %s, %s, ",
"\t%s, %s, %s, %s, %s, %s, %s, %s, ",
rna_function_string(eprop->get),
rna_function_string(eprop->set),
rna_function_string(eprop->item_fn),
rna_function_string(eprop->get_ex),
rna_function_string(eprop->set_ex),
rna_function_string(eprop->get_transform),
rna_function_string(eprop->set_transform),
rna_function_string(eprop->get_default));
if (eprop->item) {
const char *item_global_id = rna_enum_id_from_pointer(eprop->item);

View File

@@ -2538,29 +2538,36 @@ void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, Proper
/* Property Data */
static bool property_boolean_get(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
if (prop_rna_or_id.idprop) {
return IDP_Bool(prop_rna_or_id.idprop);
}
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(prop_rna_or_id.rnaprop);
if (bprop->get) {
return bprop->get(ptr);
}
if (bprop->get_ex) {
return bprop->get_ex(ptr, &bprop->property);
}
return bprop->defaultvalue;
}
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
bool value;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
value = IDP_Bool(idprop);
}
else if (bprop->get) {
value = bprop->get(ptr);
}
else if (bprop->get_ex) {
value = bprop->get_ex(ptr, prop);
}
else {
value = bprop->defaultvalue;
}
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(prop_rna_or_id.rnaprop);
BLI_assert(ELEM(value, false, true));
bool value = property_boolean_get(ptr, prop_rna_or_id);
if (bprop->get_transform) {
value = bprop->get_transform(ptr, &bprop->property, value, prop_rna_or_id.is_set);
}
return value;
}
@@ -2574,17 +2581,23 @@ bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) == false);
BLI_assert(ELEM(value, false, true));
/* just in case other values are passed */
BLI_assert(ELEM(value, true, false));
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(prop_rna_or_id.rnaprop);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (bprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const bool curr_value = property_boolean_get(ptr, prop_rna_or_id);
value = bprop->set_transform(ptr, &bprop->property, value, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
IDP_Bool(idprop) = value;
rna_idproperty_touch(idprop);
}
@@ -2592,19 +2605,19 @@ void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
bprop->set(ptr, value);
}
else if (bprop->set_ex) {
bprop->set_ex(ptr, prop, value);
bprop->set_ex(ptr, &bprop->property, value);
}
else if (prop->flag & PROP_EDITABLE) {
else if (bprop->property.flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
#ifdef USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, int(value), IDP_FLAG_STATIC_TYPE)
blender::bke::idprop::create(prop_rna_or_id.identifier, int(value), IDP_FLAG_STATIC_TYPE)
.release());
#else
IDP_AddToGroup(
group,
blender::bke::idprop::create_bool(prop->identifier, value, IDP_FLAG_STATIC_TYPE)
blender::bke::idprop::create_bool(prop_rna_or_id.identifier, value, IDP_FLAG_STATIC_TYPE)
.release());
#endif
}
@@ -2661,46 +2674,73 @@ static void rna_property_boolean_get_default_array_values(PointerRNA *ptr,
bprop->defaultarray, length, bprop->defaultvalue, out_length, r_values);
}
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
static void property_boolean_get_array(PointerRNA *ptr,
PropertyRNAOrID &prop_rna_or_id,
blender::MutableSpan<bool> r_values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (prop->arraydimension == 0) {
values[0] = RNA_property_boolean_get(ptr, prop);
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(rna_prop);
if (prop_rna_or_id.idprop) {
IDProperty *idprop = prop_rna_or_id.idprop;
BLI_assert(idprop->len == RNA_property_array_length(ptr, rna_prop) ||
(rna_prop->flag & PROP_IDPROPERTY));
if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_boolean_get(ptr, rna_prop);
}
else if (idprop->subtype == IDP_INT) {
/* Some boolean IDProperty arrays might be saved in files as an integer
* array property, since the boolean IDProperty type was added later. */
int *values_src = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values[i] = bool(values_src[i]);
const int *values_src = static_cast<const int *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
r_values[i] = bool(values_src[i]);
}
}
else if (idprop->subtype == IDP_BOOLEAN) {
bool *values_src = static_cast<bool *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
values[i] = values_src[i];
r_values[i] = values_src[i];
}
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_boolean_get(ptr, prop);
else if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_boolean_get(ptr, rna_prop);
}
else if (bprop->getarray) {
bprop->getarray(ptr, values);
bprop->getarray(ptr, r_values.data());
}
else if (bprop->getarray_ex) {
bprop->getarray_ex(ptr, prop, values);
bprop->getarray_ex(ptr, rna_prop, r_values.data());
}
else {
rna_property_boolean_get_default_array_values(ptr, bprop, values);
rna_property_boolean_get_default_array_values(ptr, bprop, r_values.data());
}
}
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(prop_rna_or_id.rnaprop);
blender::MutableSpan<bool> r_values(values, int64_t(prop_rna_or_id.array_len));
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
property_boolean_get_array(ptr, prop_rna_or_id, r_values);
if (bprop->getarray_transform) {
/* NOTE: Given current implementation, it would _probably_ be safe to use `values` for both
* input 'current values' and output 'final values', since python will make a copy of the input
* anyways. Think it's better to keep it clean and make a copy here to avoid any potential
* issues in the future though. */
blender::Array<bool, RNA_STACK_ARRAY> curr_values(r_values.as_span());
bprop->getarray_transform(
ptr, &bprop->property, curr_values.data(), prop_rna_or_id.is_set, r_values.data());
}
}
void RNA_property_boolean_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
bool *values,
@@ -2749,61 +2789,104 @@ bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int inde
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_BOOLEAN);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (prop->arraydimension == 0) {
IDP_Int(idprop) = values[0];
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
BoolPropertyRNA *bprop = reinterpret_cast<BoolPropertyRNA *>(rna_prop);
const int64_t values_num = int64_t(prop_rna_or_id.array_len);
blender::Span<bool> final_values(values, values_num);
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
/* Default init does not allocate anything, so it's cheap. This is only reinitialized with actual
* `values_num` items if `setarray_transform` is called. */
blender::Array<bool, RNA_STACK_ARRAY> final_values_storage{};
if (bprop->setarray_transform) {
/* Get raw, untransformed (aka 'storage') value. */
blender::Array<bool, RNA_STACK_ARRAY> curr_values(values_num);
property_boolean_get_array(ptr, prop_rna_or_id, curr_values.as_mutable_span());
final_values_storage.reinitialize(values_num);
bprop->setarray_transform(ptr,
rna_prop,
final_values.data(),
curr_values.data(),
prop_rna_or_id.is_set,
final_values_storage.data());
final_values = final_values_storage.as_span();
}
if (idprop) {
/* Support writing to integer and boolean IDProperties, since boolean
* RNA properties used to be stored with integer IDProperties. */
if (rna_prop->arraydimension == 0) {
if (idprop->subtype == IDP_BOOLEAN) {
IDP_Bool(idprop) = final_values[0];
}
else {
BLI_assert(idprop->subtype == IDP_INT);
IDP_Int(idprop) = final_values[0];
}
}
else {
BLI_assert(idprop->type = IDP_ARRAY);
BLI_assert(idprop->len == values_num);
if (idprop->subtype == IDP_BOOLEAN) {
memcpy(IDP_Array(idprop), values, sizeof(int8_t) * idprop->len);
memcpy(IDP_Array(idprop),
final_values.data(),
sizeof(decltype(final_values)::value_type) * idprop->len);
}
else if (idprop->subtype == IDP_INT) {
/* Support writing to integer and boolean IDProperties, since boolean
* RNA properties used to be stored with integer IDProperties. */
else {
BLI_assert(idprop->subtype == IDP_INT);
int *values_dst = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values_dst[i] = int(values[i]);
for (int i = 0; i < idprop->len; i++) {
values_dst[i] = int(final_values[i]);
}
}
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_boolean_set(ptr, prop, values[0]);
else if (rna_prop->arraydimension == 0) {
RNA_property_boolean_set(ptr, rna_prop, final_values[0]);
}
else if (bprop->setarray) {
bprop->setarray(ptr, values);
bprop->setarray(ptr, final_values.data());
}
else if (bprop->setarray_ex) {
bprop->setarray_ex(ptr, prop, values);
bprop->setarray_ex(ptr, rna_prop, final_values.data());
}
else if (prop->flag & PROP_EDITABLE) {
IDPropertyTemplate val = {0};
val.array.len = prop->totarraylength;
else if (rna_prop->flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDPropertyTemplate val = {0};
val.array.len = rna_prop->totarraylength;
#ifdef USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
val.array.type = IDP_INT;
val.array.type = IDP_INT;
#else
val.array.type = IDP_BOOLEAN;
val.array.type = IDP_BOOLEAN;
#endif
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
idprop = IDP_New(IDP_ARRAY, &val, prop->identifier, IDP_FLAG_STATIC_TYPE);
idprop = IDP_New(IDP_ARRAY, &val, prop_rna_or_id.identifier, IDP_FLAG_STATIC_TYPE);
IDP_AddToGroup(group, idprop);
#ifdef USE_INT_IDPROPS_FOR_BOOLEAN_RNA_PROP
int *values_dst = static_cast<int *>(IDP_Array(idprop));
for (uint i = 0; i < idprop->len; i++) {
values_dst[i] = values[i];
for (int i = 0; i < idprop->len; i++) {
values_dst[i] = int(final_values[i]);
}
#else
bool *values_dst = static_cast<bool *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
values_dst[i] = final_values[i];
}
#endif
}
}
}
void RNA_property_boolean_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const bool *values,
@@ -2963,38 +3046,59 @@ bool RNA_property_boolean_get_default_index(PointerRNA *ptr, PropertyRNA *prop,
return value;
}
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
static int property_int_get(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
return IDP_Int(idprop);
if (prop_rna_or_id.idprop) {
return IDP_Int(prop_rna_or_id.idprop);
}
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(prop_rna_or_id.rnaprop);
if (iprop->get) {
return iprop->get(ptr);
}
if (iprop->get_ex) {
return iprop->get_ex(ptr, prop);
return iprop->get_ex(ptr, &iprop->property);
}
return iprop->defaultvalue;
}
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_INT);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(prop_rna_or_id.rnaprop);
int value = property_int_get(ptr, prop_rna_or_id);
if (iprop->get_transform) {
value = iprop->get_transform(ptr, &iprop->property, value, prop_rna_or_id.is_set);
}
return value;
}
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) == false);
/* useful to check on bad values but set function should clamp */
// BLI_assert(RNA_property_int_clamp(ptr, prop, &value) == 0);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
RNA_property_int_clamp(ptr, prop, &value);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(prop_rna_or_id.rnaprop);
if (iprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const int curr_value = property_int_get(ptr, prop_rna_or_id);
value = iprop->set_transform(ptr, &iprop->property, value, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
IDP_Int(idprop) = value;
rna_idproperty_touch(idprop);
}
@@ -3002,14 +3106,14 @@ void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
iprop->set(ptr, value);
}
else if (iprop->set_ex) {
iprop->set_ex(ptr, prop, value);
iprop->set_ex(ptr, &iprop->property, value);
}
else if (prop->flag & PROP_EDITABLE) {
RNA_property_int_clamp(ptr, prop, &value);
else if (iprop->property.flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, value, IDP_FLAG_STATIC_TYPE).release());
blender::bke::idprop::create(prop_rna_or_id.identifier, value, IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
@@ -3046,37 +3150,64 @@ static void rna_property_int_get_default_array_values(PointerRNA *ptr,
iprop->defaultarray, length, iprop->defaultvalue, out_length, r_values);
}
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
static void property_int_get_array(PointerRNA *ptr,
PropertyRNAOrID &prop_rna_or_id,
blender::MutableSpan<int> r_values)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
values[0] = RNA_property_int_get(ptr, prop);
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(rna_prop);
if (prop_rna_or_id.idprop) {
IDProperty *idprop = prop_rna_or_id.idprop;
BLI_assert(idprop->len == RNA_property_array_length(ptr, rna_prop) ||
(rna_prop->flag & PROP_IDPROPERTY));
if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_int_get(ptr, rna_prop);
}
else {
memcpy(values, IDP_Array(idprop), sizeof(int) * idprop->len);
memcpy(r_values.data(),
IDP_Array(idprop),
sizeof(decltype(r_values)::value_type) * idprop->len);
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_int_get(ptr, prop);
else if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_int_get(ptr, rna_prop);
}
else if (iprop->getarray) {
iprop->getarray(ptr, values);
iprop->getarray(ptr, r_values.data());
}
else if (iprop->getarray_ex) {
iprop->getarray_ex(ptr, prop, values);
iprop->getarray_ex(ptr, rna_prop, r_values.data());
}
else {
rna_property_int_get_default_array_values(ptr, iprop, values);
rna_property_int_get_default_array_values(ptr, iprop, r_values.data());
}
}
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
BLI_assert(RNA_property_type(prop) == PROP_INT);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(prop_rna_or_id.rnaprop);
blender::MutableSpan<int> r_values(values, int64_t(prop_rna_or_id.array_len));
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
property_int_get_array(ptr, prop_rna_or_id, r_values);
if (iprop->getarray_transform) {
/* NOTE: Given current implementation, it would _probably_ be safe to use `values` for both
* input 'current values' and output 'final values', since python will make a copy of the input
* anyways. Think it's better to keep it clean and make a copy here to avoid any potential
* issues in the future though. */
blender::Array<int, RNA_STACK_ARRAY> curr_values(r_values.as_span());
iprop->getarray_transform(
ptr, &iprop->property, curr_values.data(), prop_rna_or_id.is_set, r_values.data());
}
}
void RNA_property_int_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
int *values,
@@ -3157,45 +3288,71 @@ int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
{
using namespace blender;
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_INT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
IDP_Int(idprop) = values[0];
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
IntPropertyRNA *iprop = reinterpret_cast<IntPropertyRNA *>(rna_prop);
const int64_t values_num = int64_t(prop_rna_or_id.array_len);
blender::Span<int> final_values(values, values_num);
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
/* Default init does not allocate anything, so it's cheap. This is only reinitialized with actual
* `values_num` items if `setarray_transform` is called. */
blender::Array<int, RNA_STACK_ARRAY> final_values_storage{};
if (iprop->setarray_transform) {
/* Get raw, untransformed (aka 'storage') value. */
blender::Array<int, RNA_STACK_ARRAY> curr_values(values_num);
property_int_get_array(ptr, prop_rna_or_id, curr_values.as_mutable_span());
final_values_storage.reinitialize(values_num);
iprop->setarray_transform(ptr,
rna_prop,
final_values.data(),
curr_values.data(),
prop_rna_or_id.is_set,
final_values_storage.data());
final_values = final_values_storage.as_span();
}
if (idprop) {
BLI_assert(idprop->len == values_num);
if (rna_prop->arraydimension == 0) {
IDP_Int(idprop) = final_values[0];
}
else {
memcpy(IDP_Array(idprop), values, sizeof(int) * idprop->len);
memcpy(IDP_Array(idprop),
final_values.data(),
sizeof(decltype(final_values)::value_type) * idprop->len);
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_int_set(ptr, prop, values[0]);
else if (rna_prop->arraydimension == 0) {
RNA_property_int_set(ptr, rna_prop, final_values[0]);
}
else if (iprop->setarray) {
iprop->setarray(ptr, values);
iprop->setarray(ptr, final_values.data());
}
else if (iprop->setarray_ex) {
iprop->setarray_ex(ptr, prop, values);
iprop->setarray_ex(ptr, rna_prop, final_values.data());
}
else if (prop->flag & PROP_EDITABLE) {
else if (rna_prop->flag & PROP_EDITABLE) {
// RNA_property_int_clamp_array(ptr, prop, &value); /* TODO. */
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(group,
bke::idprop::create(prop->identifier,
Span(values, prop->totarraylength),
IDP_FLAG_STATIC_TYPE)
blender::bke::idprop::create(
prop_rna_or_id.identifier, final_values, IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
void RNA_property_int_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const int *values,
@@ -3332,62 +3489,86 @@ int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int i
return value;
}
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
static float property_float_get(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) == false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (prop_rna_or_id.idprop) {
IDProperty *idprop = prop_rna_or_id.idprop;
if (idprop->type == IDP_FLOAT) {
return IDP_Float(idprop);
}
return float(IDP_Double(idprop));
}
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(prop_rna_or_id.rnaprop);
if (fprop->get) {
return fprop->get(ptr);
}
if (fprop->get_ex) {
return fprop->get_ex(ptr, prop);
return fprop->get_ex(ptr, &fprop->property);
}
return fprop->defaultvalue;
}
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
{
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(prop_rna_or_id.rnaprop);
float value = property_float_get(ptr, prop_rna_or_id);
if (fprop->get_transform) {
value = fprop->get_transform(ptr, &fprop->property, value, prop_rna_or_id.is_set);
}
return value;
}
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) == false);
/* useful to check on bad values but set function should clamp */
// BLI_assert(RNA_property_float_clamp(ptr, prop, &value) == 0);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
RNA_property_float_clamp(ptr, prop, &value);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(prop_rna_or_id.rnaprop);
if (fprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const float curr_value = property_float_get(ptr, prop_rna_or_id);
value = fprop->set_transform(ptr, &fprop->property, value, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
if (idprop->type == IDP_FLOAT) {
IDP_Float(idprop) = value;
}
else {
IDP_Double(idprop) = value;
IDP_Double(idprop) = double(value);
}
rna_idproperty_touch(idprop);
}
else if (fprop->set) {
fprop->set(ptr, value);
}
else if (fprop->set_ex) {
fprop->set_ex(ptr, prop, value);
fprop->set_ex(ptr, &fprop->property, value);
}
else if (prop->flag & PROP_EDITABLE) {
RNA_property_float_clamp(ptr, prop, &value);
else if (fprop->property.flag & PROP_EDITABLE) {
/* FIXME: This is only called here? What about already existing IDProps (see above)? And
* similar code for Int properties? */
RNA_property_float_clamp(ptr, &fprop->property, &value);
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop->identifier, value, IDP_FLAG_STATIC_TYPE).release());
blender::bke::idprop::create(prop_rna_or_id.identifier, value, IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
@@ -3438,49 +3619,77 @@ static void rna_property_float_get_default_array_values(PointerRNA *ptr,
}
int length = fprop->property.totarraylength;
int out_length = RNA_property_array_length(ptr, (PropertyRNA *)fprop);
int out_length = RNA_property_array_length(ptr, &fprop->property);
rna_property_float_fill_default_array_values(
fprop->defaultarray, length, fprop->defaultvalue, out_length, r_values);
}
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
static void property_float_get_array(PointerRNA *ptr,
PropertyRNAOrID &prop_rna_or_id,
blender::MutableSpan<float> r_values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
int i;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
values[0] = RNA_property_float_get(ptr, prop);
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(rna_prop);
if (prop_rna_or_id.idprop) {
IDProperty *idprop = prop_rna_or_id.idprop;
BLI_assert(idprop->len == RNA_property_array_length(ptr, rna_prop) ||
(rna_prop->flag & PROP_IDPROPERTY));
if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_float_get(ptr, rna_prop);
}
else if (idprop->subtype == IDP_FLOAT) {
memcpy(values, IDP_Array(idprop), sizeof(float) * idprop->len);
memcpy(r_values.data(),
IDP_Array(idprop),
sizeof(decltype(r_values)::value_type) * idprop->len);
}
else {
for (i = 0; i < idprop->len; i++) {
values[i] = float(((double *)IDP_Array(idprop))[i]);
double *src_values = static_cast<double *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
r_values[i] = float(src_values[i]);
}
}
}
else if (prop->arraydimension == 0) {
values[0] = RNA_property_float_get(ptr, prop);
else if (rna_prop->arraydimension == 0) {
r_values[0] = RNA_property_float_get(ptr, rna_prop);
}
else if (fprop->getarray) {
fprop->getarray(ptr, values);
fprop->getarray(ptr, r_values.data());
}
else if (fprop->getarray_ex) {
fprop->getarray_ex(ptr, prop, values);
fprop->getarray_ex(ptr, rna_prop, r_values.data());
}
else {
rna_property_float_get_default_array_values(ptr, fprop, values);
rna_property_float_get_default_array_values(ptr, fprop, r_values.data());
}
}
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(prop_rna_or_id.rnaprop);
blender::MutableSpan<float> r_values(values, int64_t(prop_rna_or_id.array_len));
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
property_float_get_array(ptr, prop_rna_or_id, r_values);
if (fprop->getarray_transform) {
/* NOTE: Given current implementation, it would _probably_ be safe to use `values` for both
* input 'current values' and output 'final values', since python will make a copy of the input
* anyways. Think it's better to keep it clean and make a copy here to avoid any potential
* issues in the future though. */
blender::Array<float, RNA_STACK_ARRAY> curr_values(r_values.as_span());
fprop->getarray_transform(
ptr, &fprop->property, curr_values.data(), prop_rna_or_id.is_set, r_values.data());
}
}
void RNA_property_float_get_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
float *values,
@@ -3561,55 +3770,82 @@ float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
IDProperty *idprop;
int i;
BLI_assert(RNA_property_type(prop) == PROP_FLOAT);
BLI_assert(RNA_property_array_check(prop) != false);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
BLI_assert(idprop->len == RNA_property_array_length(ptr, prop) ||
(prop->flag & PROP_IDPROPERTY));
if (prop->arraydimension == 0) {
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
PropertyRNA *rna_prop = prop_rna_or_id.rnaprop;
FloatPropertyRNA *fprop = reinterpret_cast<FloatPropertyRNA *>(rna_prop);
const int64_t values_num = int64_t(prop_rna_or_id.array_len);
blender::Span<float> final_values(values, values_num);
values = nullptr; /* Do not access this 'raw' pointer anymore in code below. */
/* Default init does not allocate anything, so it's cheap. This is only reinitialized with actual
* `values_num` items if `setarray_transform` is called. */
blender::Array<float, RNA_STACK_ARRAY> final_values_storage{};
if (fprop->setarray_transform) {
/* Get raw, untransformed (aka 'storage') value. */
blender::Array<float, RNA_STACK_ARRAY> curr_values(values_num);
property_float_get_array(ptr, prop_rna_or_id, curr_values.as_mutable_span());
final_values_storage.reinitialize(values_num);
fprop->setarray_transform(ptr,
rna_prop,
final_values.data(),
curr_values.data(),
prop_rna_or_id.is_set,
final_values_storage.data());
final_values = final_values_storage.as_span();
}
if (idprop) {
BLI_assert(idprop->len == values_num);
if (rna_prop->arraydimension == 0) {
if (idprop->type == IDP_FLOAT) {
IDP_Float(idprop) = values[0];
IDP_Float(idprop) = final_values[0];
}
else {
IDP_Double(idprop) = values[0];
IDP_Double(idprop) = double(final_values[0]);
}
}
else if (idprop->subtype == IDP_FLOAT) {
memcpy(IDP_Array(idprop), values, sizeof(float) * idprop->len);
memcpy(IDP_Array(idprop),
final_values.data(),
sizeof(decltype(final_values)::value_type) * idprop->len);
}
else {
for (i = 0; i < idprop->len; i++) {
((double *)IDP_Array(idprop))[i] = values[i];
double *dst_values = static_cast<double *>(IDP_Array(idprop));
for (int i = 0; i < idprop->len; i++) {
dst_values[i] = double(final_values[i]);
}
}
rna_idproperty_touch(idprop);
}
else if (prop->arraydimension == 0) {
RNA_property_float_set(ptr, prop, values[0]);
else if (rna_prop->arraydimension == 0) {
RNA_property_float_set(ptr, rna_prop, final_values[0]);
}
else if (fprop->setarray) {
fprop->setarray(ptr, values);
fprop->setarray(ptr, final_values.data());
}
else if (fprop->setarray_ex) {
fprop->setarray_ex(ptr, prop, values);
fprop->setarray_ex(ptr, rna_prop, final_values.data());
}
else if (prop->flag & PROP_EDITABLE) {
else if (rna_prop->flag & PROP_EDITABLE) {
// RNA_property_float_clamp_array(ptr, prop, &value); /* TODO. */
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(group,
blender::bke::idprop::create(prop->identifier,
blender::Span(values, prop->totarraylength),
IDP_FLAG_STATIC_TYPE)
blender::bke::idprop::create(
prop_rna_or_id.identifier, final_values, IDP_FLAG_STATIC_TYPE)
.release());
}
}
}
void RNA_property_float_set_array_at_most(PointerRNA *ptr,
PropertyRNA *prop,
const float *values,
@@ -3744,67 +3980,80 @@ float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, i
return value;
}
static size_t property_string_length_storage(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
if (prop_rna_or_id.idprop) {
IDProperty *idprop = prop_rna_or_id.idprop;
if (idprop->subtype == IDP_STRING_SUB_BYTE) {
return size_t(idprop->len);
}
/* these _must_ stay in sync */
if (strlen(IDP_String(idprop)) != idprop->len - 1) {
printf("%zu vs. %d\n", strlen(IDP_String(idprop)), idprop->len - 1);
}
BLI_assert(strlen(IDP_String(idprop)) == idprop->len - 1);
return size_t(idprop->len - 1);
}
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if (sprop->length) {
return sprop->length(ptr);
}
if (sprop->length_ex) {
return size_t(sprop->length_ex(ptr, &sprop->property));
}
return strlen(sprop->defaultvalue);
}
static std::string property_string_get(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
if (prop_rna_or_id.idprop) {
const size_t length = property_string_length_storage(ptr, prop_rna_or_id);
return std::string{IDP_String(prop_rna_or_id.idprop), length};
}
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if (sprop->get) {
const size_t length = property_string_length_storage(ptr, prop_rna_or_id);
/* Note: after `resize()` the underlying buffer is actually at least
* `length + 1` bytes long, because (since C++11) `std::string` guarantees
* a terminating null byte, but that is not considered part of the length. */
std::string string_ret;
string_ret.resize(length);
sprop->get(ptr, string_ret.data());
return string_ret;
}
if (sprop->get_ex) {
return sprop->get_ex(ptr, &sprop->property);
}
return sprop->defaultvalue;
}
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop);
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
const size_t length = size_t(RNA_property_string_length(ptr, prop));
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
/* For normal strings, the length does not contain the null terminator. But for
* #IDP_STRING_SUB_BYTE, it contains the full string including any terminating null. */
return std::string{IDP_String(idprop), length};
std::string string_ret = property_string_get(ptr, prop_rna_or_id);
if (sprop->get_transform) {
string_ret = sprop->get_transform(ptr, &sprop->property, string_ret, prop_rna_or_id.is_set);
}
if (!sprop->get && !sprop->get_ex) {
return std::string{sprop->defaultvalue};
}
std::string string_ret{};
/* Note: after `resize()` the underlying buffer is actually at least
* `length + 1` bytes long, because (since C++11) `std::string` guarantees
* a terminating null byte, but that is not considered part of the length. */
string_ret.resize(length);
if (sprop->get) {
sprop->get(ptr, string_ret.data());
}
else { /* if (sprop->get_ex) */
sprop->get_ex(ptr, prop, string_ret.data());
}
BLI_assert_msg(!sprop->maxlength || string_ret.size() < sprop->maxlength,
"Returned string exceeds the property's max length");
return string_ret;
}
void RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop, char *value)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
const std::string string_ret = RNA_property_string_get(ptr, prop);
BLI_assert(RNA_property_type(prop) == PROP_STRING);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
/* editing bytes is not 100% supported
* since they can contain NIL chars */
if (idprop->subtype == IDP_STRING_SUB_BYTE) {
memcpy(value, IDP_String(idprop), idprop->len);
value[idprop->len] = '\0';
}
else {
memcpy(value, IDP_String(idprop), idprop->len);
}
}
else if (sprop->get) {
sprop->get(ptr, value);
}
else if (sprop->get_ex) {
sprop->get_ex(ptr, prop, value);
}
else {
strcpy(value, sprop->defaultvalue);
}
memcpy(value, string_ret.c_str(), string_ret.size() + 1);
}
char *RNA_property_string_get_alloc(
@@ -3814,33 +4063,19 @@ char *RNA_property_string_get_alloc(
BLI_string_debug_size(fixedbuf, fixedlen);
}
const std::string string_ret = RNA_property_string_get(ptr, prop);
char *buf;
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
length = RNA_property_string_length(ptr, prop);
if (length + 1 < fixedlen) {
if (string_ret.size() < fixedlen) {
buf = fixedbuf;
}
else {
buf = MEM_malloc_arrayN<char>(size_t(length) + 1, __func__);
buf = MEM_malloc_arrayN<char>(string_ret.size() + 1, __func__);
}
#ifndef NDEBUG
/* safety check to ensure the string is actually set */
buf[length] = 255;
#endif
RNA_property_string_get(ptr, prop, buf);
#ifndef NDEBUG
BLI_assert(buf[length] == '\0');
#endif
memcpy(buf, string_ret.c_str(), string_ret.size() + 1);
if (r_len) {
*r_len = length;
*r_len = int(string_ret.size());
}
return buf;
@@ -3848,93 +4083,104 @@ char *RNA_property_string_get_alloc(
int RNA_property_string_length(PointerRNA *ptr, PropertyRNA *prop)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
prop = nullptr;
/* NOTE: `prop` is kept unchanged, to allow e.g. call to `RNA_property_string_get` without
* further complications.
* `sprop->property` should be used when access to an actual RNA property is required.
*/
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
if (idprop->subtype == IDP_STRING_SUB_BYTE) {
return idprop->len;
}
#ifndef NDEBUG
/* these _must_ stay in sync */
BLI_assert(strlen(IDP_String(idprop)) == idprop->len - 1);
#endif
return idprop->len - 1;
/* If there is a `get_transform` callback, no choice but get that final string to find out its
* length. Otherwise, get the 'storage length', whcih is typically more efficient to compute. */
if (sprop->get_transform) {
std::string string_final = property_string_get(ptr, prop_rna_or_id);
return int(string_final.size());
}
if (sprop->length) {
return sprop->length(ptr);
}
if (sprop->length_ex) {
return sprop->length_ex(ptr, prop);
}
return strlen(sprop->defaultvalue);
return int(property_string_length_storage(ptr, prop_rna_or_id));
}
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
std::string value_set = value;
if (sprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const std::string curr_value = property_string_get(ptr, prop_rna_or_id);
value_set = sprop->set_transform(
ptr, &sprop->property, value_set, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
/* both IDP_STRING_SUB_BYTE / IDP_STRING_SUB_UTF8 */
IDP_AssignStringMaxSize(idprop, value, RNA_property_string_maxlength(prop));
IDP_AssignStringMaxSize(
idprop, value_set.c_str(), RNA_property_string_maxlength(&sprop->property));
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
sprop->set(ptr, value); /* set function needs to clamp itself */
sprop->set(ptr, value_set.c_str()); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
sprop->set_ex(ptr, &sprop->property, value_set); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDP_AddToGroup(
group,
IDP_NewStringMaxSize(
value, RNA_property_string_maxlength(prop), prop->identifier, IDP_FLAG_STATIC_TYPE));
else if (sprop->property.flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(group,
IDP_NewStringMaxSize(value_set.c_str(),
RNA_property_string_maxlength(&sprop->property),
prop_rna_or_id.identifier,
IDP_FLAG_STATIC_TYPE));
}
}
}
void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const char *value, int len)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
BLI_assert(RNA_property_subtype(prop) == PROP_BYTESTRING);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
StringPropertyRNA *sprop = reinterpret_cast<StringPropertyRNA *>(prop_rna_or_id.rnaprop);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
IDP_ResizeArray(idprop, len);
memcpy(idprop->data.pointer, value, size_t(len));
std::string value_set = {value, size_t(len)};
if (sprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const std::string curr_value = property_string_get(ptr, prop_rna_or_id);
value_set = sprop->set_transform(
ptr, &sprop->property, value_set, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
IDP_ResizeArray(idprop, value_set.size() + 1);
memcpy(idprop->data.pointer, value, value_set.size() + 1);
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
/* XXX, should take length argument (currently not used). */
sprop->set(ptr, value); /* set function needs to clamp itself */
sprop->set(ptr, value_set.c_str()); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
/* XXX, should take length argument (currently not used). */
sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
sprop->set_ex(ptr, &sprop->property, value_set); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
else if (sprop->property.flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDPropertyTemplate val = {0};
val.string.str = value;
val.string.len = len;
val.string.str = value_set.c_str();
val.string.len = value_set.size() + 1;
val.string.subtype = IDP_STRING_SUB_BYTE;
IDP_AddToGroup(group, IDP_New(IDP_STRING, &val, prop->identifier, IDP_FLAG_STATIC_TYPE));
IDP_AddToGroup(group,
IDP_New(IDP_STRING, &val, prop_rna_or_id.identifier, IDP_FLAG_STATIC_TYPE));
}
}
}
@@ -4050,33 +4296,59 @@ std::optional<std::string> RNA_property_string_path_filter(const bContext *C,
return sprop->path_filter(C, ptr, rna_prop);
}
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
static int property_enum_get(PointerRNA *ptr, PropertyRNAOrID &prop_rna_or_id)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
return IDP_Int(idprop);
if (prop_rna_or_id.idprop) {
return IDP_Int(prop_rna_or_id.idprop);
}
EnumPropertyRNA *eprop = reinterpret_cast<EnumPropertyRNA *>(prop_rna_or_id.rnaprop);
if (eprop->get) {
return eprop->get(ptr);
}
if (eprop->get_ex) {
return eprop->get_ex(ptr, prop);
return eprop->get_ex(ptr, &eprop->property);
}
return eprop->defaultvalue;
}
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
IDProperty *idprop;
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
if ((idprop = rna_idproperty_check(&prop, ptr))) {
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
EnumPropertyRNA *eprop = reinterpret_cast<EnumPropertyRNA *>(prop_rna_or_id.rnaprop);
int value = property_enum_get(ptr, prop_rna_or_id);
if (eprop->get_transform) {
value = eprop->get_transform(ptr, &eprop->property, value, prop_rna_or_id.is_set);
}
return value;
}
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
{
BLI_assert(RNA_property_type(prop) == PROP_ENUM);
PropertyRNAOrID prop_rna_or_id;
rna_property_rna_or_id_get(prop, ptr, &prop_rna_or_id);
BLI_assert(!prop_rna_or_id.is_array);
/* Make initial `prop` pointer invalid, to ensure that it is not used anywhere below. */
prop = nullptr;
IDProperty *idprop = prop_rna_or_id.idprop;
EnumPropertyRNA *eprop = reinterpret_cast<EnumPropertyRNA *>(prop_rna_or_id.rnaprop);
if (eprop->set_transform) {
/* Get raw, untransformed (aka 'storage') value. */
const int curr_value = property_enum_get(ptr, prop_rna_or_id);
value = eprop->set_transform(ptr, &eprop->property, value, curr_value, prop_rna_or_id.is_set);
}
if (idprop) {
IDP_Int(idprop) = value;
rna_idproperty_touch(idprop);
}
@@ -4084,17 +4356,14 @@ void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
eprop->set(ptr, value);
}
else if (eprop->set_ex) {
eprop->set_ex(ptr, prop, value);
eprop->set_ex(ptr, &eprop->property, value);
}
else if (prop->flag & PROP_EDITABLE) {
IDPropertyTemplate val = {0};
IDProperty *group;
val.i = value;
group = RNA_struct_system_idprops(ptr, true);
if (group) {
IDP_AddToGroup(group, IDP_New(IDP_INT, &val, prop->identifier, IDP_FLAG_STATIC_TYPE));
else if (eprop->property.flag & PROP_EDITABLE) {
if (IDProperty *group = RNA_struct_system_idprops(ptr, true)) {
IDP_AddToGroup(
group,
blender::bke::idprop::create(prop_rna_or_id.identifier, value, IDP_FLAG_STATIC_TYPE)
.release());
}
}
}

View File

@@ -3312,7 +3312,9 @@ void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const ch
void RNA_def_property_boolean_funcs_runtime(PropertyRNA *prop,
BooleanPropertyGetFunc getfunc,
BooleanPropertySetFunc setfunc)
BooleanPropertySetFunc setfunc,
BooleanPropertyGetTransformFunc get_transform_fn,
BooleanPropertySetTransformFunc set_transform_fn)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
@@ -3331,11 +3333,21 @@ void RNA_def_property_boolean_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
bprop->get_transform = get_transform_fn;
}
if (set_transform_fn) {
bprop->set_transform = set_transform_fn;
}
}
void RNA_def_property_boolean_array_funcs_runtime(PropertyRNA *prop,
BooleanArrayPropertyGetFunc getfunc,
BooleanArrayPropertySetFunc setfunc)
void RNA_def_property_boolean_array_funcs_runtime(
PropertyRNA *prop,
BooleanArrayPropertyGetFunc getfunc,
BooleanArrayPropertySetFunc setfunc,
BooleanArrayPropertyGetTransformFunc get_transform_fn,
BooleanArrayPropertySetTransformFunc set_transform_fn)
{
BoolPropertyRNA *bprop = (BoolPropertyRNA *)prop;
@@ -3354,6 +3366,13 @@ void RNA_def_property_boolean_array_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
bprop->getarray_transform = get_transform_fn;
}
if (set_transform_fn) {
bprop->setarray_transform = set_transform_fn;
}
}
void RNA_def_property_int_funcs(PropertyRNA *prop,
@@ -3403,7 +3422,9 @@ void RNA_def_property_int_funcs(PropertyRNA *prop,
void RNA_def_property_int_funcs_runtime(PropertyRNA *prop,
IntPropertyGetFunc getfunc,
IntPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc)
IntPropertyRangeFunc rangefunc,
IntPropertyGetTransformFunc get_transform_fn,
IntPropertySetTransformFunc set_transform_fn)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
@@ -3425,12 +3446,21 @@ void RNA_def_property_int_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
iprop->get_transform = get_transform_fn;
}
if (set_transform_fn) {
iprop->set_transform = set_transform_fn;
}
}
void RNA_def_property_int_array_funcs_runtime(PropertyRNA *prop,
IntArrayPropertyGetFunc getfunc,
IntArrayPropertySetFunc setfunc,
IntPropertyRangeFunc rangefunc)
IntPropertyRangeFunc rangefunc,
IntArrayPropertyGetTransformFunc get_transform_fn,
IntArrayPropertySetTransformFunc set_transform_fn)
{
IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
@@ -3452,6 +3482,13 @@ void RNA_def_property_int_array_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
iprop->getarray_transform = get_transform_fn;
}
if (set_transform_fn) {
iprop->setarray_transform = set_transform_fn;
}
}
void RNA_def_property_float_funcs(PropertyRNA *prop,
@@ -3501,7 +3538,9 @@ void RNA_def_property_float_funcs(PropertyRNA *prop,
void RNA_def_property_float_funcs_runtime(PropertyRNA *prop,
FloatPropertyGetFunc getfunc,
FloatPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc)
FloatPropertyRangeFunc rangefunc,
FloatPropertyGetTransformFunc get_transform_fn,
FloatPropertySetTransformFunc set_transform_fn)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
@@ -3523,12 +3562,22 @@ void RNA_def_property_float_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
fprop->get_transform = get_transform_fn;
}
if (set_transform_fn) {
fprop->set_transform = set_transform_fn;
}
}
void RNA_def_property_float_array_funcs_runtime(PropertyRNA *prop,
FloatArrayPropertyGetFunc getfunc,
FloatArrayPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc)
void RNA_def_property_float_array_funcs_runtime(
PropertyRNA *prop,
FloatArrayPropertyGetFunc getfunc,
FloatArrayPropertySetFunc setfunc,
FloatPropertyRangeFunc rangefunc,
FloatArrayPropertyGetTransformFunc get_transform_fn,
FloatArrayPropertySetTransformFunc set_transform_fn)
{
FloatPropertyRNA *fprop = (FloatPropertyRNA *)prop;
@@ -3550,6 +3599,13 @@ void RNA_def_property_float_array_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
fprop->getarray_transform = get_transform_fn;
}
if (set_transform_fn) {
fprop->setarray_transform = set_transform_fn;
}
}
void RNA_def_property_enum_funcs(PropertyRNA *prop,
@@ -3589,7 +3645,9 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop,
void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
EnumPropertyGetFunc getfunc,
EnumPropertySetFunc setfunc,
EnumPropertyItemFunc itemfunc)
EnumPropertyItemFunc itemfunc,
EnumPropertyGetTransformFunc get_transform_fn,
EnumPropertySetTransformFunc set_transform_fn)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
@@ -3611,6 +3669,13 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
eprop->get_transform = get_transform_fn;
}
if (set_transform_fn) {
eprop->set_transform = set_transform_fn;
}
}
void RNA_def_property_string_funcs(PropertyRNA *prop,
@@ -3699,7 +3764,9 @@ void RNA_def_property_string_filepath_filter_func(PropertyRNA *prop, const char
void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
StringPropertyGetFunc getfunc,
StringPropertyLengthFunc lengthfunc,
StringPropertySetFunc setfunc)
StringPropertySetFunc setfunc,
StringPropertyGetTransformFunc get_transform_fn,
StringPropertySetTransformFunc set_transform_fn)
{
StringPropertyRNA *sprop = (StringPropertyRNA *)prop;
@@ -3721,6 +3788,13 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop,
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
}
if (get_transform_fn) {
sprop->get_transform = get_transform_fn;
}
if (set_transform_fn) {
sprop->set_transform = set_transform_fn;
}
}
void RNA_def_property_string_search_func_runtime(PropertyRNA *prop,

View File

@@ -103,6 +103,9 @@ using PropCollectionAssignIntFunc = bool (*)(PointerRNA *ptr,
const PointerRNA *assign_ptr);
/* Extended versions with #PropertyRNA argument. */
/* NOTE: All extended get/set callbacks will always get a 'real' PropertyRNA `prop` pointer, never
* an 'IDProperty as PropertyRNA' one (i.e. when called, the given `prop` is the RNA result of a
* call to `rna_property_rna_or_id_get` or one of its wrappers). */
using PropBooleanGetFuncEx = bool (*)(PointerRNA *ptr, PropertyRNA *prop);
using PropBooleanSetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, bool value);
@@ -120,12 +123,35 @@ using PropFloatArrayGetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, flo
using PropFloatArraySetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, const float *values);
using PropFloatRangeFuncEx = void (*)(
PointerRNA *ptr, PropertyRNA *prop, float *min, float *max, float *softmin, float *softmax);
using PropStringGetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, char *value);
using PropStringGetFuncEx = std::string (*)(PointerRNA *ptr, PropertyRNA *prop);
using PropStringLengthFuncEx = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using PropStringSetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, const char *value);
using PropStringSetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, const std::string &value);
using PropEnumGetFuncEx = int (*)(PointerRNA *ptr, PropertyRNA *prop);
using PropEnumSetFuncEx = void (*)(PointerRNA *ptr, PropertyRNA *prop, int value);
/* Transform step (applied after getting, or before setting the value). Currently only used by
* `bpy`, more details in the documentation of #BPyPropStore. */
/* NOTE: All transform get/set callbacks will always get a 'real' PropertyRNA `prop` pointer, never
* an 'IDProperty as PropertyRNA' one (i.e. when called, the given `prop` is the RNA result of a
* call to `rna_property_rna_or_id_get` or one of its wrappers). */
using PropBooleanGetTransformFunc = BooleanPropertyGetTransformFunc;
using PropBooleanSetTransformFunc = BooleanPropertySetTransformFunc;
using PropBooleanArrayGetTransformFunc = BooleanArrayPropertyGetTransformFunc;
using PropBooleanArraySetTransformFunc = BooleanArrayPropertySetTransformFunc;
using PropIntGetTransformFunc = IntPropertyGetTransformFunc;
using PropIntSetTransformFunc = IntPropertySetTransformFunc;
using PropIntArrayGetTransformFunc = IntArrayPropertyGetTransformFunc;
using PropIntArraySetTransformFunc = IntArrayPropertySetTransformFunc;
using PropFloatGetTransformFunc = FloatPropertyGetTransformFunc;
using PropFloatSetTransformFunc = FloatPropertySetTransformFunc;
using PropFloatArrayGetTransformFunc = FloatArrayPropertyGetTransformFunc;
using PropFloatArraySetTransformFunc = FloatArrayPropertySetTransformFunc;
using PropStringGetTransformFunc = StringPropertyGetTransformFunc;
using PropStringSetTransformFunc = StringPropertySetTransformFunc;
using PropEnumGetTransformFunc = EnumPropertyGetTransformFunc;
using PropEnumSetTransformFunc = EnumPropertySetTransformFunc;
/* Handling override operations, and also comparison. */
/** Structure storing all needed data to process all three kinds of RNA properties. */
@@ -463,6 +489,11 @@ struct BoolPropertyRNA {
PropBooleanArrayGetFuncEx getarray_ex;
PropBooleanArraySetFuncEx setarray_ex;
PropBooleanGetTransformFunc get_transform;
PropBooleanSetTransformFunc set_transform;
PropBooleanArrayGetTransformFunc getarray_transform;
PropBooleanArraySetTransformFunc setarray_transform;
PropBooleanGetFuncEx get_default;
PropBooleanArrayGetFuncEx get_default_array;
bool defaultvalue;
@@ -484,6 +515,11 @@ struct IntPropertyRNA {
PropIntArraySetFuncEx setarray_ex;
PropIntRangeFuncEx range_ex;
PropIntGetTransformFunc get_transform;
PropIntSetTransformFunc set_transform;
PropIntArrayGetTransformFunc getarray_transform;
PropIntArraySetTransformFunc setarray_transform;
PropertyScaleType ui_scale_type;
int softmin, softmax;
int hardmin, hardmax;
@@ -510,6 +546,11 @@ struct FloatPropertyRNA {
PropFloatArraySetFuncEx setarray_ex;
PropFloatRangeFuncEx range_ex;
PropFloatGetTransformFunc get_transform;
PropFloatSetTransformFunc set_transform;
PropFloatArrayGetTransformFunc getarray_transform;
PropFloatArraySetTransformFunc setarray_transform;
PropertyScaleType ui_scale_type;
float softmin, softmax;
float hardmin, hardmax;
@@ -531,9 +572,14 @@ struct StringPropertyRNA {
PropStringSetFunc set;
PropStringGetFuncEx get_ex;
/* This callback only returns the 'storage' length (i.e. length of string returned by `get_ex`),
* _not_ the final length (potentially modified by the `get_transform` callback). */
PropStringLengthFuncEx length_ex;
PropStringSetFuncEx set_ex;
PropStringGetTransformFunc get_transform;
PropStringSetTransformFunc set_transform;
/**
* Optional callback to list candidates for a string.
* This is only for use as suggestions in UI, other values may be assigned.
@@ -565,6 +611,9 @@ struct EnumPropertyRNA {
PropEnumGetFuncEx get_ex;
PropEnumSetFuncEx set_ex;
PropEnumGetTransformFunc get_transform;
PropEnumSetTransformFunc set_transform;
PropEnumGetFuncEx get_default;
const EnumPropertyItem *item;

View File

@@ -159,6 +159,7 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
};
/* Descriptions for rna_enum_property_flag_items and rna_enum_property_flag_enum_items. */
static constexpr auto PROP_READ_ONLY_DESCR = "When set, the property cannot be edited";
static constexpr auto PROP_HIDDEN_DESCR =
"For operators: hide from places in the user interface where Blender would add the property "
"automatically, like Adjust Last Operation. Also this property is not written to presets.";
@@ -183,6 +184,19 @@ static constexpr auto PROP_PATH_SUPPORTS_TEMPLATES_DESCR =
static constexpr auto PROP_ENUM_FLAG_DESCR = "";
const EnumPropertyItem rna_enum_property_flag_items[] = {
/* NOTE: This is used only in the `bpy.props` module to define runtime RNA properties.
* The value of this 'READ_ONLY' enum item is logically inverted compared to the
* `PROP_EDITABLE` used everywhere else in RNA-related code.
*
* This inversion logic is handled by the bpy property definition code (see
* #bpy_prop_assign_flag), and does not affect any other code area.
*
* This special handling is done to allow python property definitions to create by default
* editable properties, without having to specify the `options={'EDITABLE', ...}` parameter all
* the time.
*/
{PROP_EDITABLE, "READ_ONLY", 0, "Read Only", PROP_READ_ONLY_DESCR},
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", PROP_HIDDEN_DESCR},
{PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", PROP_SKIP_SAVE_DESCR},
{PROP_SKIP_PRESET, "SKIP_PRESET", 0, "Skip Preset", PROP_SKIP_PRESET_DESCR},
@@ -214,6 +228,19 @@ const EnumPropertyItem rna_enum_property_flag_items[] = {
/** Only for enum type properties. */
const EnumPropertyItem rna_enum_property_flag_enum_items[] = {
/* NOTE: This is used only in the `bpy.props` module to define runtime RNA properties.
* The value of this 'READ_ONLY' enum item is logically inverted compared to the
* `PROP_EDITABLE` used everywhere else in RNA-related code.
*
* This inversion logic is handled by the bpy property definition code (see
* #bpy_prop_assign_flag), and does not affect any other code area.
*
* This special handling is done to allow python property definitions to create by default
* editable properties, without having to specify the `options={'EDITABLE', ...}` parameter all
* the time.
*/
{PROP_EDITABLE, "READ_ONLY", 0, "Read Only", PROP_READ_ONLY_DESCR},
{PROP_HIDDEN, "HIDDEN", 0, "Hidden", PROP_HIDDEN_DESCR},
{PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", PROP_SKIP_SAVE_DESCR},
{PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", PROP_ANIMATABLE_DESCR},

View File

@@ -141,8 +141,12 @@ static void node_rna(StructRNA *srna)
PropertyRNA *prop;
prop = RNA_def_property(srna, "ui_shortcut", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs_runtime(
prop, rna_Node_Viewer_shortcut_node_get, rna_Node_Viewer_shortcut_node_set, nullptr);
RNA_def_property_int_funcs_runtime(prop,
rna_Node_Viewer_shortcut_node_get,
rna_Node_Viewer_shortcut_node_set,
nullptr,
nullptr,
nullptr);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_int_default(prop, NODE_VIEWER_SHORTCUT_NONE);

View File

@@ -33,7 +33,8 @@ PropertyRNA *RNA_def_node_enum(StructRNA *srna,
const bool allow_animation)
{
PropertyRNA *prop = RNA_def_property(srna, identifier, PROP_ENUM, PROP_NONE);
RNA_def_property_enum_funcs_runtime(prop, accessors.getter, accessors.setter, item_func);
RNA_def_property_enum_funcs_runtime(
prop, accessors.getter, accessors.setter, item_func, nullptr, nullptr);
RNA_def_property_enum_items(prop, static_items);
if (default_value.has_value()) {
RNA_def_property_enum_default(prop, *default_value);
@@ -59,7 +60,8 @@ PropertyRNA *RNA_def_node_boolean(StructRNA *srna,
bool allow_animation)
{
PropertyRNA *prop = RNA_def_property(srna, identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs_runtime(prop, accessors.getter, accessors.setter);
RNA_def_property_boolean_funcs_runtime(
prop, accessors.getter, accessors.setter, nullptr, nullptr);
if (default_value.has_value()) {
RNA_def_property_boolean_default(prop, *default_value);
}

View File

@@ -14,6 +14,7 @@
#define PY_SSIZE_T_CLEAN
#include <algorithm>
#include <string>
#include <Python.h>
@@ -128,9 +129,29 @@ struct BPyPropStore {
* nullptr members are skipped.
*/
struct {
/** Wrap: `RNA_def_property_*_funcs` (depending on type). */
/**
* Wrap: `RNA_def_property_*_funcs` (depending on type).
*
* - `get`/`set` are used to provide access to a non-standard storage for the value (i.e. not
* in the default 'system-defined' IDProperties storage).
* - Their fallback implementation uses the system IDProperties storage system.
* - If `get` is specified, but not `set`, the property is considered read-only.
* - If `set` is specified, but not `get`, this is an error.
* - `get_transform`/`set_transform` are used to perform some additional transformation of the
* data, after `get` is called / before `set` is called (or their matching default get/set
* implementations).
* - Their fallback implementation is 'pass-through'.
*
* Conceptually, the flow of callings is:
* - getter:
* `return get_transform(self, get(self), is_property_set(self, "prop"))`
* - setter:
* `set(self, set_transform(self, new_value, get(self), is_property_set(self, "prop")))`
*/
PyObject *get_fn;
PyObject *set_fn;
PyObject *get_transform_fn;
PyObject *set_transform_fn;
/** Wrap: #RNA_def_property_update_runtime */
PyObject *update_fn;
@@ -396,16 +417,21 @@ static PyObject *pyrna_struct_as_instance(PointerRNA *ptr)
return self;
}
static void bpy_prop_assign_flag(PropertyRNA *prop, const int flag)
static void bpy_prop_assign_flag(PropertyRNA *prop, int flag)
{
const int flag_mask = ((PROP_ANIMATABLE) & ~flag);
/* Map `READ_ONLY` to `EDITABLE`. */
flag ^= PROP_EDITABLE;
if (flag) {
RNA_def_property_flag(prop, PropertyFlag(flag));
/* The default is editable. */
const int flag_mask_set = (flag & ~PROP_EDITABLE);
const int flag_mask_clear = ((PROP_ANIMATABLE | PROP_EDITABLE) & ~flag);
if (flag_mask_set) {
RNA_def_property_flag(prop, PropertyFlag(flag_mask_set));
}
if (flag_mask) {
RNA_def_property_clear_flag(prop, PropertyFlag(flag_mask));
if (flag_mask_clear) {
RNA_def_property_clear_flag(prop, PropertyFlag(flag_mask_clear));
}
}
@@ -448,10 +474,30 @@ static void bpy_prop_gil_rna_writable_end(const BPyPropGIL_RNAWritable_State &pr
* \{ */
struct BPyPropArrayLength {
int len_total;
int len_total = 0;
/** Ignore `dims` when `dims_len == 0`. */
int dims[RNA_MAX_ARRAY_DIMENSION];
int dims_len;
int dims[RNA_MAX_ARRAY_DIMENSION] = {};
int dims_len = 0;
BPyPropArrayLength() = default;
BPyPropArrayLength(PointerRNA *ptr, PropertyRNA *prop)
{
this->len_total = RNA_property_array_length(ptr, prop);
this->dims_len = RNA_property_array_dimension(ptr, prop, this->dims);
}
bool operator==(const BPyPropArrayLength &other) const
{
if ((this->len_total != other.len_total) || (this->dims_len != other.dims_len)) {
return false;
}
for (int i = 0; i < this->dims_len; i++) {
if (this->dims[i] != other.dims[i]) {
return false;
}
}
return true;
}
};
/**
@@ -541,6 +587,51 @@ static int bpy_prop_array_from_py_with_dims(void *values,
return PyC_AsArray_Multi(values, values_elem_size, py_values, dims, dims_len, type, error_str);
}
/* NOTE: Always increases refcount of the returned value. */
static PyObject *bpy_py_object_from_prop_array_with_dims(const void *values,
const BPyPropArrayLength &array_len_info,
const PyTypeObject &type)
{
PyObject *py_values = nullptr;
if (&type == &PyBool_Type) {
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_Bool(static_cast<const bool *>(values),
uint(array_len_info.len_total));
}
else {
py_values = PyC_Tuple_PackArray_Multi_Bool(
static_cast<const bool *>(values), array_len_info.dims, array_len_info.dims_len);
}
}
else if (&type == &PyLong_Type) {
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_I32(static_cast<const int *>(values),
uint(array_len_info.len_total));
}
else {
py_values = PyC_Tuple_PackArray_Multi_I32(
static_cast<const int *>(values), array_len_info.dims, array_len_info.dims_len);
}
}
else if (&type == &PyFloat_Type) {
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_F32(static_cast<const float *>(values),
uint(array_len_info.len_total));
}
else {
/* No need for matrix column/row swapping here unless the matrix data is read directly. */
py_values = PyC_Tuple_PackArray_Multi_F32(
static_cast<const float *>(values), array_len_info.dims, array_len_info.dims_len);
}
}
else {
BLI_assert_unreachable();
}
return py_values;
}
static bool bpy_prop_array_is_matrix_compatible_ex(int subtype,
const BPyPropArrayLength *array_len_info)
{
@@ -691,6 +782,53 @@ static bool bpy_prop_boolean_get_fn(PointerRNA *ptr, PropertyRNA *prop)
return value;
}
static bool bpy_prop_boolean_get_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
bool curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args, self, PyBool_FromLong(curr_value), PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
bool ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
const int value_i = PyC_Long_AsBool(ret);
if (value_i == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = bool(value_i);
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_boolean_set_fn(PointerRNA *ptr, PropertyRNA *prop, bool value)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -728,7 +866,8 @@ static void bpy_prop_boolean_set_fn(PointerRNA *ptr, PropertyRNA *prop, bool val
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_boolean_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, bool *values)
static bool bpy_prop_boolean_set_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, bool new_value, bool curr_value, bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -736,11 +875,86 @@ static void bpy_prop_boolean_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, bo
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args,
self,
PyBool_FromLong(new_value),
PyBool_FromLong(curr_value),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
bool ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
const int value_i = PyC_Long_AsBool(ret);
if (value_i == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = bool(value_i);
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_boolean_array_from_callback_or_error(PyObject *bool_array_obj,
const BPyPropArrayLength &array_len_info,
PyObject *py_func,
bool *r_values)
{
bool is_values_set = false;
int i, len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
if (bool_array_obj != nullptr) {
if (bpy_prop_array_from_py_with_dims(r_values,
sizeof(*r_values),
bool_array_obj,
&array_len_info,
&PyBool_Type,
"BoolVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
is_values_set = true;
}
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (int i = 0; i < array_len_info.len_total; i++) {
r_values[i] = false;
}
}
Py_XDECREF(bool_array_obj);
}
static void bpy_prop_boolean_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, bool *values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
@@ -756,28 +970,40 @@ static void bpy_prop_boolean_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, bo
Py_DECREF(args);
}
if (ret != nullptr) {
if (bpy_prop_array_from_py_with_dims(values,
sizeof(*values),
ret,
&array_len_info,
&PyBool_Type,
"BoolVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
is_values_set = true;
}
Py_DECREF(ret);
bpy_prop_boolean_array_from_callback_or_error(ret, array_len_info, py_func, values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_boolean_array_get_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, const bool *curr_values, bool is_set, bool *r_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyBool_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (i = 0; i < len; i++) {
values[i] = false;
}
}
bpy_prop_boolean_array_from_callback_or_error(ret, array_len_info, py_func, r_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
@@ -790,10 +1016,7 @@ static void bpy_prop_boolean_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, co
PyObject *py_func;
PyObject *ret;
const int len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
@@ -802,16 +1025,8 @@ static void bpy_prop_boolean_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, co
{
PyObject *args = PyTuple_New(2);
PyObject *self = pyrna_struct_as_instance(ptr);
PyObject *py_values;
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_Bool(values, len);
}
else {
py_values = PyC_Tuple_PackArray_Multi_Bool(
values, array_len_info.dims, array_len_info.dims_len);
}
PyTuple_SET_ITEMS(args, self, py_values);
PyTuple_SET_ITEMS(
args, self, bpy_py_object_from_prop_array_with_dims(values, array_len_info, PyBool_Type));
ret = PyObject_CallObject(py_func, args);
@@ -833,6 +1048,45 @@ static void bpy_prop_boolean_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, co
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_boolean_array_set_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
const bool *new_values,
const bool *curr_values,
bool is_set,
bool *r_final_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(new_values, array_len_info, PyBool_Type),
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyBool_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
bpy_prop_boolean_array_from_callback_or_error(ret, array_len_info, py_func, r_final_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -846,7 +1100,6 @@ static int bpy_prop_int_get_fn(PointerRNA *ptr, PropertyRNA *prop)
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
int value;
BLI_assert(prop_store != nullptr);
@@ -865,7 +1118,7 @@ static int bpy_prop_int_get_fn(PointerRNA *ptr, PropertyRNA *prop)
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
value = 0.0f;
value = 0;
}
else {
value = PyC_Long_AsI32(ret);
@@ -883,6 +1136,51 @@ static int bpy_prop_int_get_fn(PointerRNA *ptr, PropertyRNA *prop)
return value;
}
static int bpy_prop_int_get_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
int curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args, self, PyLong_FromLong(curr_value), PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
int ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyC_Long_AsI32(ret);
if (ret_value == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_int_set_fn(PointerRNA *ptr, PropertyRNA *prop, int value)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -920,7 +1218,8 @@ static void bpy_prop_int_set_fn(PointerRNA *ptr, PropertyRNA *prop, int value)
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_int_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, int *values)
static int bpy_prop_int_set_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, int new_value, int curr_value, bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -928,11 +1227,84 @@ static void bpy_prop_int_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, int *v
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args,
self,
PyLong_FromLong(new_value),
PyLong_FromLong(curr_value),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
int ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyC_Long_AsI32(ret);
if (ret_value == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_int_array_from_callback_or_error(PyObject *int_array_obj,
const BPyPropArrayLength &array_len_info,
PyObject *py_func,
int *r_values)
{
bool is_values_set = false;
int i, len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
if (int_array_obj != nullptr) {
if (bpy_prop_array_from_py_with_dims(r_values,
sizeof(*r_values),
int_array_obj,
&array_len_info,
&PyLong_Type,
"IntVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
is_values_set = true;
}
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (int i = 0; i < array_len_info.len_total; i++) {
r_values[i] = 0;
}
}
Py_XDECREF(int_array_obj);
}
static void bpy_prop_int_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, int *values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
@@ -948,28 +1320,40 @@ static void bpy_prop_int_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, int *v
Py_DECREF(args);
}
if (ret != nullptr) {
if (bpy_prop_array_from_py_with_dims(values,
sizeof(*values),
ret,
&array_len_info,
&PyLong_Type,
"IntVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
is_values_set = true;
}
Py_DECREF(ret);
bpy_prop_int_array_from_callback_or_error(ret, array_len_info, py_func, values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_int_array_get_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, const int *curr_values, bool is_set, int *r_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyLong_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (i = 0; i < len; i++) {
values[i] = 0;
}
}
bpy_prop_int_array_from_callback_or_error(ret, array_len_info, py_func, r_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
@@ -982,10 +1366,7 @@ static void bpy_prop_int_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, const
PyObject *py_func;
PyObject *ret;
const int len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
@@ -994,16 +1375,8 @@ static void bpy_prop_int_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, const
{
PyObject *args = PyTuple_New(2);
PyObject *self = pyrna_struct_as_instance(ptr);
PyObject *py_values;
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_I32(values, len);
}
else {
py_values = PyC_Tuple_PackArray_Multi_I32(
values, array_len_info.dims, array_len_info.dims_len);
}
PyTuple_SET_ITEMS(args, self, py_values);
PyTuple_SET_ITEMS(
args, self, bpy_py_object_from_prop_array_with_dims(values, array_len_info, PyLong_Type));
ret = PyObject_CallObject(py_func, args);
@@ -1025,6 +1398,45 @@ static void bpy_prop_int_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, const
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_int_array_set_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
const int *new_values,
const int *curr_values,
bool is_set,
int *r_final_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(new_values, array_len_info, PyLong_Type),
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyLong_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
bpy_prop_int_array_from_callback_or_error(ret, array_len_info, py_func, r_final_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -1038,7 +1450,6 @@ static float bpy_prop_float_get_fn(PointerRNA *ptr, PropertyRNA *prop)
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
float value;
BLI_assert(prop_store != nullptr);
@@ -1075,6 +1486,51 @@ static float bpy_prop_float_get_fn(PointerRNA *ptr, PropertyRNA *prop)
return value;
}
static float bpy_prop_float_get_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
float curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args, self, PyFloat_FromDouble(curr_value), PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
float ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyFloat_AsDouble(ret);
if (ret_value == -1.0f && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_float_set_fn(PointerRNA *ptr, PropertyRNA *prop, float value)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -1112,7 +1568,8 @@ static void bpy_prop_float_set_fn(PointerRNA *ptr, PropertyRNA *prop, float valu
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_float_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, float *values)
static float bpy_prop_float_set_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, float new_value, float curr_value, bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -1120,11 +1577,91 @@ static void bpy_prop_float_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, floa
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args,
self,
PyFloat_FromDouble(new_value),
PyFloat_FromDouble(curr_value),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
float ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyFloat_AsDouble(ret);
if (ret_value == -1.0f && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_float_array_from_callback_or_error(PropertyRNA *prop,
PyObject *float_array_obj,
const BPyPropArrayLength &array_len_info,
PyObject *py_func,
const bool do_matrix_row_col_swap,
float *r_values)
{
bool is_values_set = false;
int i, len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
if (float_array_obj != nullptr) {
if (bpy_prop_array_from_py_with_dims(r_values,
sizeof(*r_values),
float_array_obj,
&array_len_info,
&PyFloat_Type,
"FloatVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
/* Only for float types. */
/* TODO: Clear and comnplete explanations about this matrix swap? */
if (do_matrix_row_col_swap && bpy_prop_array_is_matrix_compatible(prop, &array_len_info)) {
bpy_prop_array_matrix_swap_row_column_vn(r_values, &array_len_info);
}
is_values_set = true;
}
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (int i = 0; i < array_len_info.len_total; i++) {
r_values[i] = 0.0f;
}
}
Py_XDECREF(float_array_obj);
}
static void bpy_prop_float_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, float *values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
@@ -1140,32 +1677,45 @@ static void bpy_prop_float_array_get_fn(PointerRNA *ptr, PropertyRNA *prop, floa
Py_DECREF(args);
}
if (ret != nullptr) {
if (bpy_prop_array_from_py_with_dims(values,
sizeof(*values),
ret,
&array_len_info,
&PyFloat_Type,
"FloatVectorProperty get callback") == -1)
{
PyC_Err_PrintWithFunc(py_func);
}
else {
/* Only for float types. */
if (bpy_prop_array_is_matrix_compatible(prop, &array_len_info)) {
bpy_prop_array_matrix_swap_row_column_vn(values, &array_len_info);
}
is_values_set = true;
}
Py_DECREF(ret);
/* Custom getter always needs to perform the matrix row/col swap. */
bpy_prop_float_array_from_callback_or_error(prop, ret, array_len_info, py_func, true, values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_float_array_get_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, const float *curr_values, bool is_set, float *r_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
const BPyPropArrayLength array_len_info{ptr, prop};
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyFloat_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
if (is_values_set == false) {
/* This is the flattened length for multi-dimensional arrays. */
for (i = 0; i < len; i++) {
values[i] = 0.0f;
}
}
/* If there is a custom py-defined 'get' callback, the row/col matrix swap has already been
* performed, otherwise it needs to be done here. */
const bool do_matrix_row_col_swap = prop_store->py_data.get_fn == nullptr;
bpy_prop_float_array_from_callback_or_error(
prop, ret, array_len_info, py_func, do_matrix_row_col_swap, r_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
@@ -1178,10 +1728,7 @@ static void bpy_prop_float_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, cons
PyObject *py_func;
PyObject *ret;
const int len = RNA_property_array_length(ptr, prop);
BPyPropArrayLength array_len_info{};
array_len_info.len_total = len;
array_len_info.dims_len = RNA_property_array_dimension(ptr, prop, array_len_info.dims);
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
@@ -1190,17 +1737,8 @@ static void bpy_prop_float_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, cons
{
PyObject *args = PyTuple_New(2);
PyObject *self = pyrna_struct_as_instance(ptr);
PyObject *py_values;
if (array_len_info.dims_len == 0) {
py_values = PyC_Tuple_PackArray_F32(values, len);
}
else {
/* No need for matrix column/row swapping here unless the matrix data is read directly. */
py_values = PyC_Tuple_PackArray_Multi_F32(
values, array_len_info.dims, array_len_info.dims_len);
}
PyTuple_SET_ITEMS(args, self, py_values);
PyTuple_SET_ITEMS(
args, self, bpy_py_object_from_prop_array_with_dims(values, array_len_info, PyFloat_Type));
ret = PyObject_CallObject(py_func, args);
@@ -1222,16 +1760,90 @@ static void bpy_prop_float_array_set_fn(PointerRNA *ptr, PropertyRNA *prop, cons
bpy_prop_gil_rna_writable_end(bpy_state);
}
static void bpy_prop_float_array_set_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
const float *new_values,
const float *curr_values,
bool is_set,
float *r_final_values)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
const BPyPropArrayLength array_len_info{ptr, prop};
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
bpy_py_object_from_prop_array_with_dims(new_values, array_len_info, PyFloat_Type),
bpy_py_object_from_prop_array_with_dims(curr_values, array_len_info, PyFloat_Type),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
/* No need for matrix column/row swapping here unless the matrix data is read directly. */
bpy_prop_float_array_from_callback_or_error(
prop, ret, array_len_info, py_func, false, r_final_values);
bpy_prop_gil_rna_writable_end(bpy_state);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name String Property Callbacks
* \{ */
static void bpy_prop_string_get_fn(PointerRNA *ptr, PropertyRNA *prop, char *value)
static std::optional<std::string> bpy_prop_string_from_callback_or_error(PyObject *str_obj,
const size_t max_length,
PyObject *py_func)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
std::optional<std::string> ret_value{};
/* TODO: handle bytes strings. */
if (str_obj == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else if (!PyUnicode_Check(str_obj)) {
PyErr_Format(
PyExc_TypeError, "return value must be a string, not %.200s", Py_TYPE(str_obj)->tp_name);
PyC_Err_PrintWithFunc(py_func);
}
else {
/* NOTE: Python returns the length _without_ the `\0` terminator. */
Py_ssize_t length;
const char *ret_cstr = PyUnicode_AsUTF8AndSize(str_obj, &length);
if (max_length && size_t(length) + 1 > max_length) {
PyErr_Format(PyExc_ValueError,
"return string must be of max length %zu, not %d",
max_length - 1,
length);
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = {ret_cstr, size_t(length)};
}
}
Py_XDECREF(str_obj);
return ret_value;
}
static std::string bpy_prop_string_get_locked_fn(PointerRNA *ptr, PropertyRNA *prop)
{
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
@@ -1250,75 +1862,82 @@ static void bpy_prop_string_get_fn(PointerRNA *ptr, PropertyRNA *prop, char *val
Py_DECREF(args);
}
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
value[0] = '\0';
}
else if (!PyUnicode_Check(ret)) {
PyErr_Format(
PyExc_TypeError, "return value must be a string, not %.200s", Py_TYPE(ret)->tp_name);
PyC_Err_PrintWithFunc(py_func);
value[0] = '\0';
Py_DECREF(ret);
}
else {
Py_ssize_t length;
const char *buffer = PyUnicode_AsUTF8AndSize(ret, &length);
memcpy(value, buffer, length + 1);
Py_DECREF(ret);
}
return bpy_prop_string_from_callback_or_error(ret, RNA_property_string_maxlength(prop), py_func)
.value_or("");
}
static std::string bpy_prop_string_get_fn(PointerRNA *ptr, PropertyRNA *prop)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
std::string ret_value = bpy_prop_string_get_locked_fn(ptr, prop);
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static std::string bpy_prop_string_get_transform_locked_fn(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &curr_value,
bool is_set)
{
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
/* TODO: handle bytes strings. */
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
PyUnicode_FromStringAndSize(curr_value.c_str(), Py_ssize_t(curr_value.size())),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
return bpy_prop_string_from_callback_or_error(ret, RNA_property_string_maxlength(prop), py_func)
.value_or(curr_value);
}
static std::string bpy_prop_string_get_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
std::string ret_value = bpy_prop_string_get_transform_locked_fn(ptr, prop, curr_value, is_set);
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static int bpy_prop_string_length_fn(PointerRNA *ptr, PropertyRNA *prop)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
int length;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_fn;
{
PyObject *args = PyTuple_New(1);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args, self);
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
length = 0;
}
else if (!PyUnicode_Check(ret)) {
PyErr_Format(
PyExc_TypeError, "return value must be a string, not %.200s", Py_TYPE(ret)->tp_name);
PyC_Err_PrintWithFunc(py_func);
length = 0;
Py_DECREF(ret);
}
else {
Py_ssize_t length_ssize = 0;
PyUnicode_AsUTF8AndSize(ret, &length_ssize);
length = length_ssize;
Py_DECREF(ret);
}
/* This bpyprops-specific length callback is only called when there is a custom `get` function.
*/
std::string ret = bpy_prop_string_get_locked_fn(ptr, prop);
const int length = int(ret.size());
bpy_prop_gil_rna_writable_end(bpy_state);
return length;
}
static void bpy_prop_string_set_fn(PointerRNA *ptr, PropertyRNA *prop, const char *value)
static void bpy_prop_string_set_fn(PointerRNA *ptr, PropertyRNA *prop, const std::string &value)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -1334,9 +1953,19 @@ static void bpy_prop_string_set_fn(PointerRNA *ptr, PropertyRNA *prop, const cha
PyObject *args = PyTuple_New(2);
PyObject *self = pyrna_struct_as_instance(ptr);
PyObject *py_value = PyUnicode_FromString(value);
/* TODO: handle bytes strings. */
const size_t max_length = RNA_property_string_maxlength(prop);
if (max_length && value.size() >= max_length) {
PyErr_Format(PyExc_ValueError,
"the given string must be of max length %zu, not %zu",
max_length - 1,
value.size());
PyC_Err_PrintWithFunc(py_func);
}
PyObject *py_value = PyUnicode_FromStringAndSize(value.c_str(), value.size());
if (!py_value) {
PyErr_SetString(PyExc_ValueError, "the set value must be a valid string");
PyErr_SetString(PyExc_ValueError,
"the given string value cannot be converted into a python string");
PyC_Err_PrintWithFunc(py_func);
py_value = Py_None;
Py_INCREF(py_value);
@@ -1363,6 +1992,46 @@ static void bpy_prop_string_set_fn(PointerRNA *ptr, PropertyRNA *prop, const cha
bpy_prop_gil_rna_writable_end(bpy_state);
}
static std::string bpy_prop_string_set_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
const std::string &new_value,
const std::string &curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(
args,
self,
PyUnicode_FromStringAndSize(new_value.c_str(), Py_ssize_t(new_value.size())),
PyUnicode_FromStringAndSize(curr_value.c_str(), Py_ssize_t(curr_value.size())),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
std::string ret_value = bpy_prop_string_from_callback_or_error(
ret, RNA_property_string_maxlength(prop), py_func)
.value_or(curr_value);
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static bool bpy_prop_string_visit_fn_call(
PyObject *py_func,
PyObject *item,
@@ -1572,7 +2241,6 @@ static int bpy_prop_enum_get_fn(PointerRNA *ptr, PropertyRNA *prop)
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
int value;
BLI_assert(prop_store != nullptr);
@@ -1609,6 +2277,51 @@ static int bpy_prop_enum_get_fn(PointerRNA *ptr, PropertyRNA *prop)
return value;
}
static int bpy_prop_enum_get_transform_fn(PointerRNA *ptr,
PropertyRNA *prop,
int curr_value,
bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.get_transform_fn;
{
PyObject *args = PyTuple_New(3);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args, self, PyLong_FromLong(curr_value), PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
int ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyC_Long_AsI32(ret);
if (ret_value == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
static void bpy_prop_enum_set_fn(PointerRNA *ptr, PropertyRNA *prop, int value)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
@@ -1646,6 +2359,53 @@ static void bpy_prop_enum_set_fn(PointerRNA *ptr, PropertyRNA *prop, int value)
bpy_prop_gil_rna_writable_end(bpy_state);
}
static int bpy_prop_enum_set_transform_fn(
PointerRNA *ptr, PropertyRNA *prop, int new_value, int curr_value, bool is_set)
{
const BPyPropGIL_RNAWritable_State bpy_state = bpy_prop_gil_rna_writable_begin();
BPyPropStore *prop_store = static_cast<BPyPropStore *>(RNA_property_py_data_get(prop));
PyObject *py_func;
PyObject *ret;
BLI_assert(prop_store != nullptr);
py_func = prop_store->py_data.set_transform_fn;
{
PyObject *args = PyTuple_New(4);
PyObject *self = pyrna_struct_as_instance(ptr);
PyTuple_SET_ITEMS(args,
self,
PyLong_FromLong(new_value),
PyLong_FromLong(curr_value),
PyBool_FromLong(is_set));
ret = PyObject_CallObject(py_func, args);
Py_DECREF(args);
}
int ret_value = curr_value;
if (ret == nullptr) {
PyC_Err_PrintWithFunc(py_func);
}
else {
ret_value = PyC_Long_AsI32(ret);
if (ret_value == -1 && PyErr_Occurred()) {
PyC_Err_PrintWithFunc(py_func);
ret_value = curr_value;
}
Py_DECREF(ret);
}
bpy_prop_gil_rna_writable_end(bpy_state);
return ret_value;
}
/* utility function we need for parsing int's in an if statement */
static bool py_long_as_int(PyObject *py_long, int *r_int)
{
@@ -1998,10 +2758,16 @@ static void bpy_prop_callback_assign_pointer(PropertyRNA *prop, PyObject *poll_f
}
}
static void bpy_prop_callback_assign_boolean(PropertyRNA *prop, PyObject *get_fn, PyObject *set_fn)
static bool bpy_prop_callback_assign_boolean(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
BooleanPropertyGetFunc rna_get_fn = nullptr;
BooleanPropertySetFunc rna_set_fn = nullptr;
BooleanPropertyGetTransformFunc rna_get_transform_fn = nullptr;
BooleanPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2011,21 +2777,49 @@ static void bpy_prop_callback_assign_boolean(PropertyRNA *prop, PyObject *get_fn
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_boolean_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_boolean_funcs_runtime(prop, rna_get_fn, rna_set_fn);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_boolean_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_boolean_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_boolean_funcs_runtime(
prop, rna_get_fn, rna_set_fn, rna_get_transform_fn, rna_set_transform_fn);
return true;
}
static void bpy_prop_callback_assign_boolean_array(PropertyRNA *prop,
static bool bpy_prop_callback_assign_boolean_array(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn)
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
BooleanArrayPropertyGetFunc rna_get_fn = nullptr;
BooleanArrayPropertySetFunc rna_set_fn = nullptr;
BooleanArrayPropertyGetTransformFunc rna_get_transform_fn = nullptr;
BooleanArrayPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2035,19 +2829,49 @@ static void bpy_prop_callback_assign_boolean_array(PropertyRNA *prop,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_boolean_array_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_boolean_array_funcs_runtime(prop, rna_get_fn, rna_set_fn);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_boolean_array_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_boolean_array_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_boolean_array_funcs_runtime(
prop, rna_get_fn, rna_set_fn, rna_get_transform_fn, rna_set_transform_fn);
return true;
}
static void bpy_prop_callback_assign_int(PropertyRNA *prop, PyObject *get_fn, PyObject *set_fn)
static bool bpy_prop_callback_assign_int(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
IntPropertyGetFunc rna_get_fn = nullptr;
IntPropertySetFunc rna_set_fn = nullptr;
IntPropertyGetTransformFunc rna_get_transform_fn = nullptr;
IntPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2057,21 +2881,49 @@ static void bpy_prop_callback_assign_int(PropertyRNA *prop, PyObject *get_fn, Py
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_int_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_int_funcs_runtime(prop, rna_get_fn, rna_set_fn, nullptr);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_int_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_int_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_int_funcs_runtime(
prop, rna_get_fn, rna_set_fn, nullptr, rna_get_transform_fn, rna_set_transform_fn);
return true;
}
static void bpy_prop_callback_assign_int_array(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn)
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
IntArrayPropertyGetFunc rna_get_fn = nullptr;
IntArrayPropertySetFunc rna_set_fn = nullptr;
IntArrayPropertyGetTransformFunc rna_get_transform_fn = nullptr;
IntArrayPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2081,19 +2933,46 @@ static void bpy_prop_callback_assign_int_array(PropertyRNA *prop,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_int_array_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_int_array_funcs_runtime(prop, rna_get_fn, rna_set_fn, nullptr);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_int_array_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_int_array_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_int_array_funcs_runtime(
prop, rna_get_fn, rna_set_fn, nullptr, rna_get_transform_fn, rna_set_transform_fn);
}
static void bpy_prop_callback_assign_float(PropertyRNA *prop, PyObject *get_fn, PyObject *set_fn)
static bool bpy_prop_callback_assign_float(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
FloatPropertyGetFunc rna_get_fn = nullptr;
FloatPropertySetFunc rna_set_fn = nullptr;
FloatPropertyGetTransformFunc rna_get_transform_fn = nullptr;
FloatPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2103,21 +2982,49 @@ static void bpy_prop_callback_assign_float(PropertyRNA *prop, PyObject *get_fn,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_float_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_float_funcs_runtime(prop, rna_get_fn, rna_set_fn, nullptr);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_float_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_float_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_float_funcs_runtime(
prop, rna_get_fn, rna_set_fn, nullptr, rna_get_transform_fn, rna_set_transform_fn);
return true;
}
static void bpy_prop_callback_assign_float_array(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn)
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
FloatArrayPropertyGetFunc rna_get_fn = nullptr;
FloatArrayPropertySetFunc rna_set_fn = nullptr;
FloatArrayPropertyGetTransformFunc rna_get_transform_fn = nullptr;
FloatArrayPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2127,18 +3034,41 @@ static void bpy_prop_callback_assign_float_array(PropertyRNA *prop,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_float_array_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
RNA_def_property_float_array_funcs_runtime(prop, rna_get_fn, rna_set_fn, nullptr);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_float_array_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_float_array_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_float_array_funcs_runtime(
prop, rna_get_fn, rna_set_fn, nullptr, rna_get_transform_fn, rna_set_transform_fn);
}
static void bpy_prop_callback_assign_string(PropertyRNA *prop,
static bool bpy_prop_callback_assign_string(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn,
PyObject *search_fn,
const eStringPropertySearchFlag search_flag)
{
@@ -2146,6 +3076,8 @@ static void bpy_prop_callback_assign_string(PropertyRNA *prop,
StringPropertyLengthFunc rna_length_fn = nullptr;
StringPropertySetFunc rna_set_fn = nullptr;
StringPropertySearchFunc rna_search_fn = nullptr;
StringPropertyGetTransformFunc rna_get_transform_fn = nullptr;
StringPropertySetTransformFunc rna_set_transform_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2156,11 +3088,33 @@ static void bpy_prop_callback_assign_string(PropertyRNA *prop,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_string_set_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_fn, set_fn);
}
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_string_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_string_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
if (search_fn) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2168,20 +3122,27 @@ static void bpy_prop_callback_assign_string(PropertyRNA *prop,
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.string_data.search_fn, search_fn);
}
RNA_def_property_string_funcs_runtime(prop, rna_get_fn, rna_length_fn, rna_set_fn);
RNA_def_property_string_funcs_runtime(
prop, rna_get_fn, rna_length_fn, rna_set_fn, rna_get_transform_fn, rna_set_transform_fn);
if (rna_search_fn) {
RNA_def_property_string_search_func_runtime(prop, rna_search_fn, search_flag);
}
return true;
}
static void bpy_prop_callback_assign_enum(PropertyRNA *prop,
static bool bpy_prop_callback_assign_enum(PropertyRNA *prop,
PyObject *get_fn,
PyObject *set_fn,
PyObject *itemf_fn)
PyObject *itemf_fn,
PyObject *get_transform_fn,
PyObject *set_transform_fn)
{
EnumPropertyGetFunc rna_get_fn = nullptr;
EnumPropertyItemFunc rna_itemf_fn = nullptr;
EnumPropertySetFunc rna_set_fn = nullptr;
EnumPropertyGetTransformFunc rna_get_transform_fn = nullptr;
EnumPropertySetTransformFunc rna_set_transform_fn = nullptr;
EnumPropertyItemFunc rna_itemf_fn = nullptr;
if (get_fn && get_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
@@ -2191,6 +3152,13 @@ static void bpy_prop_callback_assign_enum(PropertyRNA *prop,
}
if (set_fn && set_fn != Py_None) {
if (!rna_get_fn) {
PyErr_SetString(PyExc_ValueError,
"The `set` callback is defined without a matching `get` function, this is "
"not supported. `set_transform` should probably be used instead?");
return false;
}
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_fn = bpy_prop_enum_set_fn;
@@ -2203,7 +3171,24 @@ static void bpy_prop_callback_assign_enum(PropertyRNA *prop,
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.enum_data.itemf_fn, itemf_fn);
}
RNA_def_property_enum_funcs_runtime(prop, rna_get_fn, rna_set_fn, rna_itemf_fn);
if (get_transform_fn && get_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_get_transform_fn = bpy_prop_enum_get_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.get_transform_fn, get_transform_fn);
}
if (set_transform_fn && set_transform_fn != Py_None) {
BPyPropStore *prop_store = bpy_prop_py_data_ensure(prop);
rna_set_transform_fn = bpy_prop_enum_set_transform_fn;
ASSIGN_PYOBJECT_INCREF(prop_store->py_data.set_transform_fn, set_transform_fn);
}
RNA_def_property_enum_funcs_runtime(
prop, rna_get_fn, rna_set_fn, rna_itemf_fn, rna_get_transform_fn, rna_set_transform_fn);
return true;
}
/** \} */
@@ -2435,15 +3420,51 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
"bool]\n"
#define BPY_PROPDEF_GET_DOC(ty) \
" :arg get: Function to be called when this value is 'read',\n" \
" :arg get: Function to be called when this value is 'read', and the default,\n" \
" system-defined storage is not used for this property.\n" \
" This function must take 1 value (self) and return the value of the property.\n" \
"\n" \
" .. note:: Defining this callback without a matching ``set`` one will make " \
"the property read-only (even if ``READ_ONLY`` option is not set)." \
"\n" \
" :type get: Callable[[:class:`bpy.types.bpy_struct`], " ty "]\n"
#define BPY_PROPDEF_SET_DOC(ty) \
" :arg set: Function to be called when this value is 'written',\n" \
" :arg set: Function to be called when this value is 'written', and the default,\n" \
" system-defined storage is not used for this property.\n" \
" This function must take 2 values (self, value) and return None.\n" \
"\n" \
" .. note:: Defining this callback without a matching ``get`` one is invalid." \
"\n" \
" :type set: Callable[[:class:`bpy.types.bpy_struct`, " ty "], None]\n"
#define BPY_PROPDEF_GET_TRANSFORM_DOC(ty) \
" :arg get_transform: Function to be called when this value is 'read',\n" \
" if some additional processing must be performed on the stored value.\n" \
" This function must take three arguments (self, the stored value,\n" \
" and a boolean indicating if the property is currently set),\n" \
" and return the final, transformed value of the property.\n" \
"\n" \
" .. note:: The callback is responsible to ensure that value limits of the property " \
"(min/max, length...) are respected. Otherwise a ValueError exception is raised.\n" \
"\n" \
" :type get_transform: Callable[[:class:`bpy.types.bpy_struct`, " ty ", bool], " ty "]\n"
#define BPY_PROPDEF_SET_TRANSFORM_DOC(ty) \
" :arg set_transform: Function to be called when this value is 'written',\n" \
" if some additional processing must be performed on the given value before storing it.\n" \
" This function must take four arguments (self, the given value to store,\n" \
" the currently stored value ('raw' value, without any ``get_transform`` applied to " \
"it),\n" \
" and a boolean indicating if the property is currently set),\n" \
" and return the final, transformed value of the property.\n" \
"\n" \
" .. note:: The callback is responsible to ensure that value limits (min/max, " \
"length...) are respected. Otherwise a ValueError exception is raised.\n" \
"\n" \
" :type set_transform: " \
"Callable[[:class:`bpy.types.bpy_struct`, " ty ", " ty ", bool], " ty "]\n"
#define BPY_PROPDEF_SEARCH_DOC \
" :arg search: Function to be called to show candidates for this string (shown in the UI).\n" \
" This function must take 3 values (self, context, edit_text)\n" \
@@ -2512,12 +3533,15 @@ PyDoc_STRVAR(
"subtype='NONE', "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new boolean property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_CTXT_DOC BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("bool") BPY_PROPDEF_SET_DOC("bool"));
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("bool") BPY_PROPDEF_SET_DOC("bool")
BPY_PROPDEF_GET_TRANSFORM_DOC("bool") BPY_PROPDEF_SET_TRANSFORM_DOC("bool"));
static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2555,6 +3579,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr",
"name",
@@ -2568,6 +3595,8 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
"update",
"get",
"set",
"get_transform",
"set_transform",
nullptr,
};
static _PyArg_Parser _parser = {
@@ -2585,6 +3614,8 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":BoolProperty",
_keywords,
nullptr,
@@ -2609,7 +3640,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
&subtype_enum,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -2623,6 +3656,12 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -2645,7 +3684,10 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_boolean(prop, get_fn, set_fn);
if (!bpy_prop_callback_assign_boolean(prop, get_fn, set_fn, get_transform_fn, set_transform_fn))
{
return nullptr;
}
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -2667,7 +3709,9 @@ PyDoc_STRVAR(
"size=3, "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new vector boolean property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_CTXT_DOC
@@ -2675,7 +3719,9 @@ PyDoc_STRVAR(
" :type default: Sequence[bool]\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("Sequence[bool]")
BPY_PROPDEF_SET_DOC("tuple[bool, ...]"));
BPY_PROPDEF_SET_DOC("tuple[bool, ...]")
BPY_PROPDEF_GET_TRANSFORM_DOC("Sequence[bool]")
BPY_PROPDEF_SET_TRANSFORM_DOC("Sequence[bool]"));
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2717,6 +3763,8 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr",
@@ -2732,6 +3780,8 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
"update",
"get",
"set",
"get_transform",
"set_transform",
nullptr,
};
static _PyArg_Parser _parser = {
@@ -2750,6 +3800,8 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":BoolVectorProperty",
_keywords,
nullptr,
@@ -2775,7 +3827,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
&array_len_info,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -2802,6 +3856,12 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -2836,7 +3896,7 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_boolean_array(prop, get_fn, set_fn);
bpy_prop_callback_assign_boolean_array(prop, get_fn, set_fn, get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -2860,14 +3920,17 @@ PyDoc_STRVAR(
"subtype='NONE', "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new int property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_CTXT_DOC
BPY_PROPDEF_NUM_MINMAX_DOC("int") BPY_PROPDEF_NUM_SOFT_MINMAX_DOC("int")
BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC BPY_PROPDEF_UPDATE_DOC
BPY_PROPDEF_GET_DOC("int") BPY_PROPDEF_SET_DOC("int"));
BPY_PROPDEF_GET_DOC("int") BPY_PROPDEF_SET_DOC("int")
BPY_PROPDEF_GET_TRANSFORM_DOC("int") BPY_PROPDEF_SET_TRANSFORM_DOC("int"));
static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -2907,26 +3970,15 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr",
"name",
"description",
"translation_context",
"default",
"min",
"max",
"soft_min",
"soft_max",
"step",
"options",
"override",
"tags",
"subtype",
"update",
"get",
"set",
nullptr,
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "options", "override",
"tags", "subtype", "update", "get",
"set", "get_transform", "set_transform", nullptr,
};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
@@ -2948,6 +4000,8 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":IntProperty",
_keywords,
nullptr,
@@ -2976,7 +4030,9 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
&subtype_enum,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -2990,6 +4046,12 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3014,7 +4076,7 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_int(prop, get_fn, set_fn);
bpy_prop_callback_assign_int(prop, get_fn, set_fn, get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3039,7 +4101,9 @@ PyDoc_STRVAR(
"size=3, "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new vector int property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_CTXT_DOC
@@ -3049,7 +4113,9 @@ PyDoc_STRVAR(
BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("Sequence[int]")
BPY_PROPDEF_SET_DOC("tuple[int, ...]"));
BPY_PROPDEF_SET_DOC("tuple[int, ...]")
BPY_PROPDEF_GET_TRANSFORM_DOC("Sequence[int]")
BPY_PROPDEF_SET_TRANSFORM_DOC("Sequence[int]"));
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3093,13 +4159,16 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "options", "override",
"tags", "subtype", "size", "update",
"get", "set", nullptr,
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "options", "override",
"tags", "subtype", "size", "update",
"get", "set", "get_transform", "set_transform",
nullptr,
};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
@@ -3122,6 +4191,8 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":IntVectorProperty",
_keywords,
nullptr,
@@ -3152,7 +4223,9 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
&array_len_info,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -3179,6 +4252,12 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3215,7 +4294,7 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_int_array(prop, get_fn, set_fn);
bpy_prop_callback_assign_int_array(prop, get_fn, set_fn, get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3241,7 +4320,9 @@ PyDoc_STRVAR(
"unit='NONE', "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new float (single precision) property definition.\n"
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_CTXT_DOC BPY_PROPDEF_NUM_MINMAX_DOC(
@@ -3249,7 +4330,8 @@ PyDoc_STRVAR(
BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_DOC
BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("float")
BPY_PROPDEF_SET_DOC("float"));
BPY_PROPDEF_SET_DOC("float") BPY_PROPDEF_GET_TRANSFORM_DOC("float")
BPY_PROPDEF_SET_TRANSFORM_DOC("float"));
static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3294,13 +4376,16 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "precision", "options",
"override", "tags", "subtype", "unit",
"update", "get", "set", nullptr,
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "precision", "options",
"override", "tags", "subtype", "unit",
"update", "get", "set", "get_transform",
"set_transform", nullptr,
};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
@@ -3324,6 +4409,8 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":FloatProperty",
_keywords,
nullptr,
@@ -3355,7 +4442,9 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
&unit_enum,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -3369,6 +4458,12 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3394,7 +4489,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_float(prop, get_fn, set_fn);
bpy_prop_callback_assign_float(prop, get_fn, set_fn, get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3432,7 +4527,9 @@ PyDoc_STRVAR(
BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC("Sequence[float]")
BPY_PROPDEF_SET_DOC("tuple[float, ...]"));
BPY_PROPDEF_SET_DOC("tuple[float, ...]")
BPY_PROPDEF_GET_TRANSFORM_DOC("Sequence[float]")
BPY_PROPDEF_SET_TRANSFORM_DOC("Sequence[float]"));
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3481,14 +4578,16 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "precision", "options",
"override", "tags", "subtype", "unit",
"size", "update", "get", "set",
nullptr,
"attr", "name", "description", "translation_context",
"default", "min", "max", "soft_min",
"soft_max", "step", "precision", "options",
"override", "tags", "subtype", "unit",
"size", "update", "get", "set",
"get_transform", "set_transform", nullptr,
};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
@@ -3513,6 +4612,8 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":FloatVectorProperty",
_keywords,
nullptr,
@@ -3546,7 +4647,9 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
&array_len_info,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -3576,6 +4679,12 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (id_data.prop_free_handle != nullptr) {
RNA_def_property_free_identifier_deferred_finish(srna, id_data.prop_free_handle);
@@ -3613,7 +4722,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_float_array(prop, get_fn, set_fn);
bpy_prop_callback_assign_float_array(prop, get_fn, set_fn, get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3636,6 +4745,8 @@ PyDoc_STRVAR(
"update=None, "
"get=None, "
"set=None, "
"get_transform=None, "
"set_transform=None, "
"search=None, "
"search_options={'SUGGESTION'})\n"
"\n"
@@ -3646,7 +4757,9 @@ PyDoc_STRVAR(
" :arg maxlen: maximum length of the string.\n"
" :type maxlen: int\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_STRING_DOC BPY_PROPDEF_UPDATE_DOC
BPY_PROPDEF_GET_DOC("str") BPY_PROPDEF_SET_DOC("str") BPY_PROPDEF_SEARCH_DOC);
BPY_PROPDEF_GET_DOC("str") BPY_PROPDEF_SET_DOC("str")
BPY_PROPDEF_GET_TRANSFORM_DOC("str") BPY_PROPDEF_SET_TRANSFORM_DOC("str")
BPY_PROPDEF_SEARCH_DOC);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3684,6 +4797,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
PyObject *search_fn = nullptr;
BPy_EnumProperty_Parse search_options_enum{};
search_options_enum.items = rna_enum_property_string_search_flag_items;
@@ -3703,6 +4818,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"update",
"get",
"set",
"get_transform",
"set_transform",
"search",
"search_options",
nullptr,
@@ -3723,6 +4840,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
"O" /* `search` */
"O&" /* `search_options` */
":StringProperty",
@@ -3750,6 +4869,8 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
&update_fn,
&get_fn,
&set_fn,
&get_transform_fn,
&set_transform_fn,
&search_fn,
pyrna_enum_bitfield_parse_set,
&search_options_enum))
@@ -3766,6 +4887,12 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(search_fn, "search", 3) == -1) {
return nullptr;
}
@@ -3797,8 +4924,13 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_string(
prop, get_fn, set_fn, search_fn, eStringPropertySearchFlag(search_options_enum.value));
bpy_prop_callback_assign_string(prop,
get_fn,
set_fn,
get_transform_fn,
set_transform_fn,
search_fn,
eStringPropertySearchFlag(search_options_enum.value));
RNA_def_property_duplicate_pointers(srna, prop);
Py_RETURN_NONE;
@@ -3819,7 +4951,9 @@ PyDoc_STRVAR(
"tags=set(), "
"update=None, "
"get=None, "
"set=None)\n"
"set=None, "
"get_transform=None, "
"set_transform=None)\n"
"\n"
" Returns a new enumerator property definition.\n"
"\n"
@@ -3876,7 +5010,8 @@ PyDoc_STRVAR(
" (i.e. if a callback function is given as *items* parameter).\n"
" :type default: str | int | set[str]\n" BPY_PROPDEF_OPTIONS_ENUM_DOC
BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_UPDATE_DOC
BPY_PROPDEF_GET_DOC("int") BPY_PROPDEF_SET_DOC("int"));
BPY_PROPDEF_GET_DOC("int") BPY_PROPDEF_SET_DOC("int")
BPY_PROPDEF_GET_TRANSFORM_DOC("int") BPY_PROPDEF_SET_TRANSFORM_DOC("int"));
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3914,6 +5049,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *update_fn = nullptr;
PyObject *get_fn = nullptr;
PyObject *set_fn = nullptr;
PyObject *get_transform_fn = nullptr;
PyObject *set_transform_fn = nullptr;
static const char *_keywords[] = {
"attr",
@@ -3928,6 +5065,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
"update",
"get",
"set",
"get_transform",
"set_transform",
nullptr,
};
static _PyArg_Parser _parser = {
@@ -3945,6 +5084,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
"O" /* `update` */
"O" /* `get` */
"O" /* `set` */
"O" /* `get_transform` */
"O" /* `set_transform` */
":EnumProperty",
_keywords,
nullptr,
@@ -3967,7 +5108,9 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
&tags_enum,
&update_fn,
&get_fn,
&set_fn))
&set_fn,
&get_transform_fn,
&set_transform_fn))
{
return nullptr;
}
@@ -3981,6 +5124,12 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
if (bpy_prop_callback_check(set_fn, "set", 2) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(get_transform_fn, "get_transform", 3) == -1) {
return nullptr;
}
if (bpy_prop_callback_check(set_transform_fn, "set_transform", 4) == -1) {
return nullptr;
}
if (default_py == Py_None) {
/* This allows to get same behavior when explicitly passing None as default value,
@@ -4056,7 +5205,8 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
bpy_prop_assign_flag_override(prop, override_enum.value);
}
bpy_prop_callback_assign_update(prop, update_fn);
bpy_prop_callback_assign_enum(prop, get_fn, set_fn, (is_itemf ? items : nullptr));
bpy_prop_callback_assign_enum(
prop, get_fn, set_fn, (is_itemf ? items : nullptr), get_transform_fn, set_transform_fn);
RNA_def_property_duplicate_pointers(srna, prop);
if (is_itemf == false) {

View File

@@ -69,18 +69,28 @@ def _run_runtime_group_register_access(args):
do_register = args.get("do_register", False)
do_access = args.get("do_access", False)
do_get_set = args.get("do_get_set", False)
do_transform = args.get("do_transform", False)
property_type = args.get("property_type", 'IntProperty')
property_definition_cb = getattr(bpy.props, property_type)
assert (not (do_get_set and do_transform))
# Define basic 'transform' callbacks to test setting value,
# default to just setting untransformed value for 'unknown'/undefined property types.
property_transform_cb = {
property_transform_set_cb = {
'BoolProperty': lambda v: not v,
'IntProperty': lambda v: v + 1,
'FloatVectorProperty': lambda v: [v[2] + 1.0, v[0], v[1]],
'StringProperty': lambda v: ("B" if (v and v[0] == "A") else "A") + v[1:],
}.get(property_type, lambda v: v)
property_transform_get_cb = {
'BoolProperty': lambda v: not v,
'IntProperty': lambda v: v - 1,
'FloatVectorProperty': lambda v: [v[0], v[1], v[2]],
'StringProperty': lambda v: ("B" if (v and v[0] == "A") else "A") + v[1:],
}.get(property_type, lambda v: v)
if do_get_set:
class DummyGroup(bpy.types.PropertyGroup):
dummy_prop: property_definition_cb(
@@ -95,6 +105,12 @@ def _run_runtime_group_register_access(args):
"dummy_prop",
val),
)
elif do_transform:
class DummyGroup(bpy.types.PropertyGroup):
dummy_prop: property_definition_cb(
get_transform=lambda self, curr_v, is_set: property_transform_get_cb(curr_v),
set_transform=lambda self, curr_v, new_v, is_set: property_transform_set_cb(curr_v),
)
else:
class DummyGroup(bpy.types.PropertyGroup):
dummy_prop: property_definition_cb()
@@ -115,9 +131,14 @@ def _run_runtime_group_register_access(args):
bpy.utils.register_class(DummyGroup)
bpy.types.Scene.dummy_group = bpy.props.PointerProperty(type=DummyGroup)
for i in range(iterations):
v = sce.dummy_group.dummy_prop
sce.dummy_group.dummy_prop = property_transform_cb(v)
if do_transform:
for i in range(iterations):
v = sce.dummy_group.dummy_prop
sce.dummy_group.dummy_prop = v
else:
for i in range(iterations):
v = sce.dummy_group.dummy_prop
sce.dummy_group.dummy_prop = property_transform_set_cb(v)
del bpy.types.Scene.dummy_group
bpy.utils.unregister_class(DummyGroup)
@@ -165,4 +186,10 @@ def generate(env):
{"do_access": True, "do_get_set": True, "property_type": 'FloatVectorProperty'}),
BPYRNATest("Py-Defined StringProperty Custom Get/Set Access", _run_runtime_group_register_access, 10 * 1000,
{"do_access": True, "do_get_set": True, "property_type": 'StringProperty'}),
BPYRNATest("Py-Defined BoolProperty Custom Transform Access", _run_runtime_group_register_access, 1000 * 1000,
{"do_access": True, "do_transform": True, "property_type": 'BoolProperty'}),
BPYRNATest("Py-Defined FloatVectorProperty Custom Transform Access", _run_runtime_group_register_access, 1000 * 1000,
{"do_access": True, "do_transform": True, "property_type": 'FloatVectorProperty'}),
BPYRNATest("Py-Defined StringProperty Custom Transform Access", _run_runtime_group_register_access, 1000 * 1000,
{"do_access": True, "do_transform": True, "property_type": 'StringProperty'}),
]

View File

@@ -7,6 +7,8 @@ import bpy
import rna_prop_ui
import idprop
import io
import sys
import unittest
from array import array
@@ -266,6 +268,12 @@ class TestIdPropertyDynamicRNA(TestHelper, unittest.TestCase):
string_prop: bpy.props.StringProperty()
int_prop: bpy.props.IntProperty()
float_array_prop: bpy.props.FloatVectorProperty(size=[3])
# Basic get/set transform.
string_prop_transform: bpy.props.StringProperty(
default="test",
maxlen=10,
get_transform=lambda self, storage_val, is_set: storage_val + "!!",
set_transform=lambda self, new_val, storage_val, is_set: storage_val + "!!" + new_val)
def setUp(self):
super().setUp()
@@ -348,6 +356,40 @@ class TestIdPropertyDynamicRNA(TestHelper, unittest.TestCase):
with self.assertRaises(TypeError):
self.id.bl_system_properties_get()['dynrna_prop']['float_array_prop'] = [1.0, 10.0, 100.0, 0.1]
def test_get_set_transform(self):
self.assertEqual(len(self.id.dynrna_prop.string_prop_transform), 6)
self.assertEqual(self.id.dynrna_prop.string_prop_transform, "test!!")
# Default value only, was not yet set.
self.assertFalse('string_prop_transform' in self.id.bl_system_properties_get()['dynrna_prop'])
self.id.dynrna_prop.string_prop_transform = "-"
self.assertEqual(self.id.dynrna_prop.string_prop_transform, "test!!-!!")
self.assertEqual(self.id.bl_system_properties_get()['dynrna_prop']['string_prop_transform'], "test!!-")
# Raw-set exactly maxlen - 1 char.
self.id.bl_system_properties_get()['dynrna_prop']['string_prop_transform'] = "test!!tes"
# get_transform will produce an 11-char results, which should trigger an error.
# These asserts are not raised currently, but only print in `stderr`...
# But the returned string is the 'storage' one, not the result from get_transform.
stderr, sys.stderr = sys.stderr, io.StringIO()
self.assertEqual(self.id.dynrna_prop.string_prop_transform, "test!!tes")
self.assertTrue("ValueError" in sys.stderr.getvalue() and
"10" in sys.stderr.getvalue() and "11" in sys.stderr.getvalue())
sys.stderr.close()
sys.stderr = stderr
# Raw-set back to default value.
self.id.bl_system_properties_get()['dynrna_prop']['string_prop_transform'] = "test"
# Now set_transform will return 12-char string, wich is also invalid and discarded.
stderr, sys.stderr = sys.stderr, io.StringIO()
self.id.dynrna_prop.string_prop_transform = "test!!"
self.assertTrue("ValueError" in sys.stderr.getvalue() and
"10" in sys.stderr.getvalue() and "12" in sys.stderr.getvalue())
sys.stderr.close()
sys.stderr = stderr
self.assertEqual(self.id.bl_system_properties_get()['dynrna_prop']['string_prop_transform'], "test")
self.assertEqual(self.id.dynrna_prop.string_prop_transform, "test!!")
class TestIdPropertyGroupView(TestHelper, unittest.TestCase):

View File

@@ -45,33 +45,70 @@ class TestPropNumerical(unittest.TestCase):
id_type.test_float = FloatProperty(default=float(self.default_value))
self.test_bool_storage = bool(self.custom_value)
self.test_int_storage = int(self.custom_value)
self.test_float_storage = float(self.custom_value)
def set_(s, v):
def bool_set_(s, v):
self.test_bool_storage = v
def int_set_(s, v):
self.test_int_storage = v
def float_set_(s, v):
self.test_float_storage = v
id_type.test_bool_getset = BoolProperty(
default=bool(self.default_value),
get=lambda s: self.test_bool_storage,
set=set_,
set=bool_set_,
)
self.test_int_storage = int(self.custom_value)
def set_(s, v):
self.test_int_storage = v
id_type.test_int_getset = IntProperty(
default=int(self.default_value),
get=lambda s: self.test_int_storage,
set=set_,
set=int_set_,
)
self.test_float_storage = float(self.custom_value)
def set_(s, v):
self.test_float_storage = v
id_type.test_float_getset = FloatProperty(
default=float(self.default_value),
get=lambda s: self.test_float_storage,
set=set_,
set=float_set_,
)
id_type.test_bool_transform = BoolProperty(
default=bool(self.default_value),
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_int_transform = IntProperty(
default=int(self.default_value),
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_float_transform = FloatProperty(
default=float(self.default_value),
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_bool_getset_transform = BoolProperty(
default=bool(self.default_value),
get=lambda s: self.test_bool_storage,
set=bool_set_,
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_int_getset_transform = IntProperty(
default=int(self.default_value),
get=lambda s: self.test_int_storage,
set=int_set_,
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_float_getset_transform = FloatProperty(
default=float(self.default_value),
get=lambda s: self.test_float_storage,
set=float_set_,
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
def tearDown(self):
@@ -83,6 +120,14 @@ class TestPropNumerical(unittest.TestCase):
del id_type.test_int_getset
del id_type.test_bool_getset
del id_type.test_float_transform
del id_type.test_int_transform
del id_type.test_bool_transform
del id_type.test_float_getset_transform
del id_type.test_int_getset_transform
del id_type.test_bool_getset_transform
def do_test_access(self, prop_name, py_type, expected_value):
v = getattr(id_inst, prop_name)
self.assertIsInstance(v, py_type)
@@ -110,6 +155,24 @@ class TestPropNumerical(unittest.TestCase):
def test_access_float_getset(self):
self.do_test_access("test_float_getset", float, float(self.custom_value))
def test_access_bool_transform(self):
self.do_test_access("test_bool_transform", bool, bool(self.default_value))
def test_access_int_transform(self):
self.do_test_access("test_int_transform", int, int(self.default_value))
def test_access_float_transform(self):
self.do_test_access("test_float_transform", float, float(self.default_value))
def test_access_bool_getset_transform(self):
self.do_test_access("test_bool_getset_transform", bool, bool(self.custom_value))
def test_access_int_getset_transform(self):
self.do_test_access("test_int_getset_transform", int, int(self.custom_value))
def test_access_float_getset_transform(self):
self.do_test_access("test_float_getset_transform", float, float(self.custom_value))
# TODO: Add expected failure cases (e.g. handling of out-of range values).
@@ -171,28 +234,63 @@ class TestPropEnum(unittest.TestCase):
)
self.test_enum_storage = self.enum_expected_values[self.custom_value]
def set_(s, v):
self.test_enum_storage = v
id_type.test_enum_getset = EnumProperty(
items=self.enum_items,
default=self.default_value,
get=lambda s: self.test_enum_storage,
set=set_,
)
self.test_enum_bitflag_storage = functools.reduce(
lambda a, b: a | b,
(self.enum_expected_bitflag_values[bf] for bf in self.custom_bitflag_value))
def set_(s, v):
def enum_set_(s, v):
self.test_enum_storage = v
def bitflag_set_(s, v):
self.test_enum_bitflag_storage = v
id_type.test_enum_getset = EnumProperty(
items=self.enum_items,
default=self.default_value,
get=lambda s: self.test_enum_storage,
set=enum_set_,
)
id_type.test_enum_bitflag_getset = EnumProperty(
items=self.enum_items,
default=self.default_bitflag_value,
options={"ENUM_FLAG"},
get=lambda s: self.test_enum_bitflag_storage,
set=set_,
set=bitflag_set_,
)
id_type.test_enum_transform = EnumProperty(
items=self.enum_items,
default=self.default_value,
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_enum_bitflag_transform = EnumProperty(
items=self.enum_items,
default=self.default_bitflag_value,
options={"ENUM_FLAG"},
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_enum_getset_transform = EnumProperty(
items=self.enum_items,
default=self.default_value,
get=lambda s: self.test_enum_storage,
set=enum_set_,
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
)
id_type.test_enum_bitflag_getset_transform = EnumProperty(
items=self.enum_items,
default=self.default_bitflag_value,
options={"ENUM_FLAG"},
get_transform=lambda s, c_v, isset: c_v,
set_transform=lambda s, n_v, c_v, isset: n_v,
get=lambda s: self.test_enum_bitflag_storage,
set=bitflag_set_,
)
def tearDown(self):
@@ -200,6 +298,10 @@ class TestPropEnum(unittest.TestCase):
del id_type.test_enum_bitflag
del id_type.test_enum_getset
del id_type.test_enum_bitflag_getset
del id_type.test_enum_transform
del id_type.test_enum_bitflag_transform
del id_type.test_enum_getset_transform
del id_type.test_enum_bitflag_getset_transform
# Test expected generated values for enum items.
def do_test_enum_values(self, prop_name, expected_item_values):
@@ -215,6 +317,24 @@ class TestPropEnum(unittest.TestCase):
def test_enum_bitflag_item_values(self):
self.do_test_enum_values("test_enum_bitflag", self.enum_expected_bitflag_values)
def test_enum_getset_item_values(self):
self.do_test_enum_values("test_enum_getset", self.enum_expected_values)
def test_enum_bitflag_getset_item_values(self):
self.do_test_enum_values("test_enum_bitflag_getset", self.enum_expected_bitflag_values)
def test_enum_transform_item_values(self):
self.do_test_enum_values("test_enum_transform", self.enum_expected_values)
def test_enum_bitflag_transform_item_values(self):
self.do_test_enum_values("test_enum_bitflag_transform", self.enum_expected_bitflag_values)
def test_enum_getset_transform_item_values(self):
self.do_test_enum_values("test_enum_getset_transform", self.enum_expected_values)
def test_enum_bitflag_getset_transform_item_values(self):
self.do_test_enum_values("test_enum_bitflag_getset_transform", self.enum_expected_bitflag_values)
# Test basic access to enum values.
def do_test_access(self, prop_name, py_type, expected_value):
v = getattr(id_inst, prop_name)
@@ -234,6 +354,18 @@ class TestPropEnum(unittest.TestCase):
def test_access_enum_bitflag_getset(self):
self.do_test_access("test_enum_bitflag_getset", set, self.custom_bitflag_value)
def test_access_enum_transform(self):
self.do_test_access("test_enum_transform", str, self.default_value)
def test_access_enum_bitflag_transform(self):
self.do_test_access("test_enum_bitflag_transform", set, self.default_bitflag_value)
def test_access_enum_getset_transform(self):
self.do_test_access("test_enum_getset_transform", str, self.custom_value)
def test_access_enum_bitflag_getset_transform(self):
self.do_test_access("test_enum_bitflag_getset_transform", set, self.custom_bitflag_value)
# TODO: Add expected failure cases (e.g. handling of invalid items identifiers).

View File

@@ -147,32 +147,71 @@ class TestPropArrayIndex(unittest.TestCase):
self.test_array_b_2d_storage = [[bool(v) for v in range(self.size_2d[1])] for i in range(self.size_2d[0])]
def set_(s, v):
def bool_set_(s, v):
self.test_array_b_2d_storage = v
id_type.test_array_b_2d_getset = BoolVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_b_2d_storage,
set=set_,
)
self.test_array_i_2d_storage = [[int(v) for v in range(self.size_2d[1])] for i in range(self.size_2d[0])]
def set_(s, v):
def int_set_(s, v):
self.test_array_i_2d_storage = v
id_type.test_array_i_2d_getset = IntVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_i_2d_storage,
set=set_,
)
self.test_array_f_2d_storage = [[float(v) for v in range(self.size_2d[1])] for i in range(self.size_2d[0])]
def set_(s, v):
def float_set_(s, v):
self.test_array_f_2d_storage = v
id_type.test_array_b_2d_getset = BoolVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_b_2d_storage,
set=bool_set_,
)
id_type.test_array_i_2d_getset = IntVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_i_2d_storage,
set=int_set_,
)
id_type.test_array_f_2d_getset = FloatVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_f_2d_storage,
set=set_,
set=float_set_,
)
id_type.test_array_b_3d_transform = BoolVectorProperty(
size=self.size_3d,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: not v),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: not v),
)
id_type.test_array_i_3d_transform = IntVectorProperty(
size=self.size_3d,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: v + 1),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: v - 1),
)
id_type.test_array_f_3d_transform = FloatVectorProperty(
size=self.size_3d,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: v * 2.0),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: v / 2.0),
)
id_type.test_array_b_2d_getset_transform = BoolVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_b_2d_storage,
set=bool_set_,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: not v),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: not v),
)
id_type.test_array_i_2d_getset_transform = IntVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_i_2d_storage,
set=int_set_,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: v + 1),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: v - 1),
)
id_type.test_array_f_2d_getset_transform = FloatVectorProperty(
size=self.size_2d,
get=lambda s: self.test_array_f_2d_storage,
set=float_set_,
get_transform=lambda s, c_v, isset: seq_items_xform(c_v, lambda v: v * 2.0),
set_transform=lambda s, n_v, c_v, isset: seq_items_xform(n_v, lambda v: v / 2.0),
)
def tearDown(self):
@@ -190,6 +229,14 @@ class TestPropArrayIndex(unittest.TestCase):
del id_type.test_array_i_2d_getset
del id_type.test_array_b_2d_getset
del id_type.test_array_f_3d_transform
del id_type.test_array_i_3d_transform
del id_type.test_array_b_3d_transform
del id_type.test_array_f_2d_getset_transform
del id_type.test_array_i_2d_getset_transform
del id_type.test_array_b_2d_getset_transform
@staticmethod
def compute_slice_len(s):
if not isinstance(s, slice):
@@ -297,6 +344,36 @@ class TestPropArrayIndex(unittest.TestCase):
id_inst.test_array_f_2d_getset, self.size_2d, self.valid_indices_2d, self.invalid_indices_2d
)
def test_indices_access_b_3d_transform(self):
self.do_test_indices_access(
id_inst.test_array_b_3d_transform, self.size_3d, self.valid_indices_3d, self.invalid_indices_3d
)
def test_indices_access_i_3d_transform(self):
self.do_test_indices_access(
id_inst.test_array_i_3d_transform, self.size_3d, self.valid_indices_3d, self.invalid_indices_3d
)
def test_indices_access_f_3d_transform(self):
self.do_test_indices_access(
id_inst.test_array_f_3d_transform, self.size_3d, self.valid_indices_3d, self.invalid_indices_3d
)
def test_indices_access_b_2d_getset_transform(self):
self.do_test_indices_access(
id_inst.test_array_b_2d_getset_transform, self.size_2d, self.valid_indices_2d, self.invalid_indices_2d
)
def test_indices_access_i_2d_getset_transform(self):
self.do_test_indices_access(
id_inst.test_array_i_2d_getset_transform, self.size_2d, self.valid_indices_2d, self.invalid_indices_2d
)
def test_indices_access_f_2d_getset_transform(self):
self.do_test_indices_access(
id_inst.test_array_f_2d_getset_transform, self.size_2d, self.valid_indices_2d, self.invalid_indices_2d
)
class TestPropArrayForeach(unittest.TestCase):
# Test foreach_get/_set access of Int and Float vector properties (bool ones do not support this).
@@ -499,12 +576,37 @@ class TestPropArrayMultiDimensional(unittest.TestCase):
def set_fn(id_arg, value):
local_data["array"] = value
def get_tx_fn(id_arg, curr_value, is_set):
return seq_items_xform(curr_value, lambda v: v + 1.0)
def set_tx_fn(id_arg, new_value, curr_value, is_set):
return seq_items_xform(new_value, lambda v: v - 1.0)
id_type.temp = FloatVectorProperty(size=(dim_x, dim_y), subtype='MATRIX', get=get_fn, set=set_fn)
id_inst.temp = data_native
data_as_tuple = seq_items_as_tuple(id_inst.temp)
self.assertEqual(data_as_tuple, data_native)
del id_type.temp
id_type.temp = FloatVectorProperty(
size=(dim_x, dim_y), subtype='MATRIX', get_transform=get_tx_fn, set_transform=set_tx_fn)
id_inst.temp = data_native
data_as_tuple = seq_items_as_tuple(id_inst.temp)
self.assertEqual(data_as_tuple, data_native)
del id_type.temp
id_type.temp = FloatVectorProperty(
size=(dim_x, dim_y),
subtype='MATRIX',
get=get_fn,
set=set_fn,
get_transform=get_tx_fn,
set_transform=set_tx_fn)
id_inst.temp = data_native
data_as_tuple = seq_items_as_tuple(id_inst.temp)
self.assertEqual(data_as_tuple, data_native)
del id_type.temp
def test_matrix_3x3(self):
self._test_matrix(3, 3)