diff options
-rw-r--r-- | release/scripts/modules/rna_prop_ui.py | 19 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/object.py | 44 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/wm.py | 55 | ||||
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 5 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_context_menu.c | 9 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_ops.c | 53 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_access.c | 171 |
8 files changed, 350 insertions, 9 deletions
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index fc17cc60c6c..f08390cfd6d 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -96,6 +96,25 @@ def rna_idprop_has_properties(rna_item): return (nbr_props > 1) or (nbr_props and '_RNA_UI' not in keys) +def rna_idprop_ui_prop_default_set(item, prop, value): + defvalue = None + try: + prop_type = type(item[prop]) + + if prop_type in {int, float}: + defvalue = prop_type(value) + except KeyError: + pass + + if defvalue: + rna_ui = rna_idprop_ui_prop_get(item, prop, True) + rna_ui["default"] = defvalue + else: + rna_ui = rna_idprop_ui_prop_get(item, prop) + if rna_ui and "default" in rna_ui: + del rna_ui["default"] + + def draw(layout, context, context_member, property_type, use_edit=True): def assign_props(prop, val, key): diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 949e2baff03..660f87aea0d 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -943,6 +943,49 @@ class LoadReferenceImage(LoadImageAsEmpty, Operator): pass +class OBJECT_OT_assign_property_defaults(Operator): + """Assign the current values of custom properties as their defaults, for use as part of the rest pose state in NLA track mixing""" + bl_idname = "object.assign_property_defaults" + bl_label = "Assign Custom Property Values as Default" + bl_options = {'UNDO', 'REGISTER'} + + process_data: BoolProperty(name="Process data properties", default=True) + process_bones: BoolProperty(name="Process bone properties", default=True) + + @classmethod + def poll(cls, context): + obj = context.active_object + return obj is not None and obj.library is None and obj.mode in {'POSE', 'OBJECT'} + + @staticmethod + def assign_defaults(obj): + from rna_prop_ui import rna_idprop_ui_prop_default_set + + rna_properties = {'_RNA_UI'} | {prop.identifier for prop in obj.bl_rna.properties if prop.is_runtime} + + for prop, value in obj.items(): + if prop not in rna_properties: + rna_idprop_ui_prop_default_set(obj, prop, value) + + def execute(self, context): + obj = context.active_object + + self.assign_defaults(obj) + + if self.process_bones and obj.pose: + for pbone in obj.pose.bones: + self.assign_defaults(pbone) + + if self.process_data and obj.data and obj.data.library is None: + self.assign_defaults(obj.data) + + if self.process_bones and isinstance(obj.data, bpy.types.Armature): + for bone in obj.data.bones: + self.assign_defaults(bone) + + return {'FINISHED'} + + classes = ( ClearAllRestrictRender, DupliOffsetFromCursor, @@ -958,4 +1001,5 @@ classes = ( SubdivisionSet, TransformsToDeltas, TransformsToDeltasAnim, + OBJECT_OT_assign_property_defaults, ) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index e26e2ddf214..bf968de8641 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1052,6 +1052,12 @@ rna_value = StringProperty( maxlen=1024, ) +rna_default = StringProperty( + name="Default Value", + description="Default value of the property. Important for NLA mixing", + maxlen=1024, +) + rna_property = StringProperty( name="Property Name", description="Property name edit", @@ -1089,6 +1095,7 @@ class WM_OT_properties_edit(Operator): data_path: rna_path property: rna_property value: rna_value + default: rna_default min: rna_min max: rna_max use_soft_limits: rna_use_soft_limits @@ -1107,6 +1114,28 @@ class WM_OT_properties_edit(Operator): "hard_range": (self.min, self.max), } + def get_value_eval(self): + try: + value_eval = eval(self.value) + # assert else None -> None, not "None", see [#33431] + assert(type(value_eval) in {str, float, int, bool, tuple, list}) + except: + value_eval = self.value + + return value_eval + + + def get_default_eval(self): + try: + default_eval = eval(self.default) + # assert else None -> None, not "None", see [#33431] + assert(type(default_eval) in {str, float, int, bool, tuple, list}) + except: + default_eval = self.default + + return default_eval + + def execute(self, context): from rna_prop_ui import ( rna_idprop_ui_prop_get, @@ -1124,12 +1153,8 @@ class WM_OT_properties_edit(Operator): self.report({'ERROR'}, "Direct execution not supported") return {'CANCELLED'} - try: - value_eval = eval(value) - # assert else None -> None, not "None", see [#33431] - assert(type(value_eval) in {str, float, int, bool, tuple, list}) - except: - value_eval = value + value_eval = self.get_value_eval() + default_eval = self.get_default_eval() # First remove item = eval("context.%s" % data_path) @@ -1159,6 +1184,8 @@ class WM_OT_properties_edit(Operator): if prop_type in {float, int}: prop_ui["min"] = prop_type(self.min) prop_ui["max"] = prop_type(self.max) + if type(default_eval) in {float, int} and default_eval != 0: + prop_ui["default"] = prop_type(default_eval) if self.use_soft_limits: prop_ui["soft_min"] = prop_type(self.soft_min) @@ -1223,6 +1250,13 @@ class WM_OT_properties_edit(Operator): exec_str = "item.is_property_overridable_static('[\"%s\"]')" % (self.property) self.is_overridable_static = bool(eval(exec_str)) + # default default value + prop_type = type(self.get_value_eval()) + if prop_type in {int,float}: + self.default = str(prop_type(0)) + else: + self.default = "" + # setup defaults prop_ui = rna_idprop_ui_prop_get(item, self.property, False) # don't create if prop_ui: @@ -1230,6 +1264,10 @@ class WM_OT_properties_edit(Operator): self.max = prop_ui.get("max", 1000000000) self.description = prop_ui.get("description", "") + defval = prop_ui.get("default", None) + if defval is not None: + self.default = str(defval) + self.soft_min = prop_ui.get("soft_min", self.min) self.soft_max = prop_ui.get("soft_max", self.max) self.use_soft_limits = ( @@ -1275,6 +1313,11 @@ class WM_OT_properties_edit(Operator): layout = self.layout layout.prop(self, "property") layout.prop(self, "value") + + row = layout.row() + row.enabled = type(self.get_value_eval()) in {int,float} + row.prop(self, "default") + row = layout.row(align=True) row.prop(self, "min") row.prop(self, "max") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index fa58fed6102..7922cdb90ec 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2662,6 +2662,11 @@ class VIEW3D_MT_pose_apply(Menu): layout.operator("pose.armature_apply") layout.operator("pose.visual_transform_apply") + layout.separator() + + props = layout.operator("object.assign_property_defaults") + props.process_bones = True + class VIEW3D_MT_pose_specials(Menu): bl_label = "Pose Context Menu" diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 84460f9f149..d9967625199 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -404,7 +404,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const PropertySubType subtype = RNA_property_subtype(prop); bool is_anim = RNA_property_animateable(ptr, prop); bool is_editable = RNA_property_editable(ptr, prop); - /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ + bool is_idprop = RNA_property_is_idprop(prop); bool is_set = RNA_property_is_set(ptr, prop); /* second slower test, saved people finding keyframe items in menus when its not possible */ @@ -643,6 +643,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) ICON_NONE, "UI_OT_unset_property_button"); } + if (is_idprop && !is_array_component && ELEM(type, PROP_INT, PROP_FLOAT)) { + uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Value as Default"), + ICON_NONE, "UI_OT_assign_default_button"); + + uiItemS(layout); + } + if (is_array_component) { uiItemBooleanO( layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"), diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index b4b59cae75b..1cb9f156eeb 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -301,6 +301,58 @@ static void UI_OT_reset_default_button(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); } +/* Assign Value as Default Button Operator ------------------------ */ + +static bool assign_default_button_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + if (ptr.data && prop && RNA_property_editable(&ptr, prop)) { + PropertyType type = RNA_property_type(prop); + + return RNA_property_is_idprop(prop) && !RNA_property_array_check(prop) && ELEM(type, PROP_INT, PROP_FLOAT); + } + + return false; +} + +static int assign_default_button_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + + /* try to reset the nominated setting to its default value */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + /* if there is a valid property that is editable... */ + if (ptr.data && prop && RNA_property_editable(&ptr, prop)) { + if (RNA_property_assign_default(&ptr, prop)) + return operator_button_property_finish(C, &ptr, prop); + } + + return OPERATOR_CANCELLED; +} + +static void UI_OT_assign_default_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Assign Value as Default"; + ot->idname = "UI_OT_assign_default_button"; + ot->description = "Set this property's current value as the new default"; + + /* callbacks */ + ot->poll = assign_default_button_poll; + ot->exec = assign_default_button_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + /* Unset Property Button Operator ------------------------ */ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1557,6 +1609,7 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_copy_data_path_button); WM_operatortype_append(UI_OT_copy_python_command_button); WM_operatortype_append(UI_OT_reset_default_button); + WM_operatortype_append(UI_OT_assign_default_button); WM_operatortype_append(UI_OT_unset_property_button); WM_operatortype_append(UI_OT_override_type_set_button); WM_operatortype_append(UI_OT_override_remove_button); diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f6bfcb2bb32..03a879c9cf7 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -952,6 +952,7 @@ 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); void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value); int RNA_property_int_get_default(PointerRNA *ptr, PropertyRNA *prop); +bool RNA_property_int_set_default(PointerRNA *ptr, PropertyRNA *prop, int value); void RNA_property_int_get_default_array(PointerRNA *ptr, PropertyRNA *prop, int *values); int RNA_property_int_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index); @@ -963,6 +964,7 @@ 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); void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value); float RNA_property_float_get_default(PointerRNA *ptr, PropertyRNA *prop); +bool RNA_property_float_set_default(PointerRNA *ptr, PropertyRNA *prop, float value); void RNA_property_float_get_default_array(PointerRNA *ptr, PropertyRNA *prop, float *values); float RNA_property_float_get_default_index(PointerRNA *ptr, PropertyRNA *prop, int index); @@ -1015,6 +1017,7 @@ bool RNA_property_collection_move(PointerRNA *ptr, PropertyRNA *prop, int key, i /* copy/reset */ bool RNA_property_copy(struct Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index); bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index); +bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop); /* Path * diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 2f23bc5eea9..1a212097c31 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -257,8 +257,7 @@ static void rna_idproperty_touch(IDProperty *idprop) idprop->flag &= ~IDP_FLAG_GHOST; } -/* return a UI local ID prop definition for this prop */ -static IDProperty *rna_idproperty_ui(PropertyRNA *prop) +static IDProperty *rna_idproperty_ui_container(PropertyRNA *prop) { IDProperty *idprop; @@ -274,6 +273,14 @@ static IDProperty *rna_idproperty_ui(PropertyRNA *prop) } } + return idprop; +} + +/* return a UI local ID prop definition for this prop */ +static IDProperty *rna_idproperty_ui(PropertyRNA *prop) +{ + IDProperty *idprop = rna_idproperty_ui_container(prop); + if (idprop) { return IDP_GetPropertyTypeFromGroup(idprop, ((IDProperty *)prop)->name, IDP_GROUP); } @@ -281,6 +288,94 @@ static IDProperty *rna_idproperty_ui(PropertyRNA *prop) return NULL; } +/* return or create a UI local ID prop definition for this prop */ +static IDProperty *rna_idproperty_ui_ensure(PointerRNA *ptr, PropertyRNA *prop, bool create) +{ + IDProperty *idprop = rna_idproperty_ui_container(prop); + IDPropertyTemplate dummy = { 0 }; + + if (idprop == NULL && create) { + IDProperty *props = RNA_struct_idprops(ptr, false); + + /* Sanity check: props is the actual container of this property. */ + if (props != NULL && BLI_findindex(&props->data.group, prop) >= 0) { + idprop = IDP_New(IDP_GROUP, &dummy, RNA_IDP_UI); + + if (!IDP_AddToGroup(props, idprop)) { + IDP_FreeProperty(idprop); + return NULL; + } + } + } + + if (idprop) { + const char *name = ((IDProperty *)prop)->name; + IDProperty *rv = IDP_GetPropertyTypeFromGroup(idprop, name, IDP_GROUP); + + if (rv == NULL && create) { + rv = IDP_New(IDP_GROUP, &dummy, name); + + if (!IDP_AddToGroup(idprop, rv)) { + IDP_FreeProperty(rv); + return NULL; + } + } + + return rv; + } + + return NULL; +} + +static bool rna_idproperty_ui_set_default(PointerRNA *ptr, PropertyRNA *prop, const char type, IDPropertyTemplate *value) +{ + BLI_assert(ELEM(type, IDP_INT, IDP_DOUBLE)); + + if (prop->magic == RNA_MAGIC) { + return false; + } + + /* attempt to get the local ID values */ + IDProperty *idp_ui = rna_idproperty_ui_ensure(ptr, prop, value != NULL); + + if (idp_ui == NULL) { + return (value == NULL); + } + + IDProperty *item = IDP_GetPropertyTypeFromGroup(idp_ui, "default", type); + + if (value == NULL) { + if (item != NULL) { + IDP_RemoveFromGroup(idp_ui, item); + } + } + else { + if (item != NULL) { + switch (type) { + case IDP_INT: + IDP_Int(item) = value->i; + break; + case IDP_DOUBLE: + IDP_Double(item) = value->d; + break; + default: + BLI_assert(false); + return false; + } + } + else { + item = IDP_New(type, value, "default"); + + if (!IDP_AddToGroup(idp_ui, item)) { + IDP_FreeProperty(item); + return false; + } + } + } + + return true; +} + IDProperty *RNA_struct_idprops(PointerRNA *ptr, bool create) { StructRNA *type = ptr->type; @@ -2726,9 +2821,33 @@ void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, i int RNA_property_int_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop) { IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop); + + if (prop->magic != RNA_MAGIC) { + /* attempt to get the local ID values */ + IDProperty *idp_ui = rna_idproperty_ui(prop); + + if (idp_ui) { + IDProperty *item; + + item = IDP_GetPropertyTypeFromGroup(idp_ui, "default", IDP_INT); + return item ? IDP_Int(item) : iprop->defaultvalue; + } + } + return iprop->defaultvalue; } +bool RNA_property_int_set_default(PointerRNA *ptr, PropertyRNA *prop, int value) +{ + if (value != 0) { + IDPropertyTemplate val = { .i = value }; + return rna_idproperty_ui_set_default(ptr, prop, IDP_INT, &val); + } + else { + return rna_idproperty_ui_set_default(ptr, prop, IDP_INT, NULL); + } +} + void RNA_property_int_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA *prop, int *values) { IntPropertyRNA *iprop = (IntPropertyRNA *)rna_ensure_property(prop); @@ -3023,9 +3142,32 @@ float RNA_property_float_get_default(PointerRNA *UNUSED(ptr), PropertyRNA *prop) BLI_assert(RNA_property_type(prop) == PROP_FLOAT); BLI_assert(RNA_property_array_check(prop) == false); + if (prop->magic != RNA_MAGIC) { + /* attempt to get the local ID values */ + IDProperty *idp_ui = rna_idproperty_ui(prop); + + if (idp_ui) { + IDProperty *item; + + item = IDP_GetPropertyTypeFromGroup(idp_ui, "default", IDP_DOUBLE); + return item ? IDP_Double(item) : fprop->defaultvalue; + } + } + return fprop->defaultvalue; } +bool RNA_property_float_set_default(PointerRNA *ptr, PropertyRNA *prop, float value) +{ + if (value != 0) { + IDPropertyTemplate val = { .d = value }; + return rna_idproperty_ui_set_default(ptr, prop, IDP_DOUBLE, &val); + } + else { + return rna_idproperty_ui_set_default(ptr, prop, IDP_DOUBLE, NULL); + } +} + void RNA_property_float_get_default_array(PointerRNA *UNUSED(ptr), PropertyRNA *prop, float *values) { FloatPropertyRNA *fprop = (FloatPropertyRNA *)rna_ensure_property(prop); @@ -7257,6 +7399,31 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index) } } +bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop) +{ + if (!RNA_property_is_idprop(prop) || RNA_property_array_check(prop)) { + return false; + } + + /* get and set the default values as appropriate for the various types */ + switch (RNA_property_type(prop)) { + case PROP_INT: + { + int value = RNA_property_int_get(ptr, prop); + return RNA_property_int_set_default(ptr, prop, value); + } + + case PROP_FLOAT: + { + float value = RNA_property_float_get(ptr, prop); + return RNA_property_float_set_default(ptr, prop, value); + } + + default: + return false; + } +} + static bool rna_property_override_operation_apply( Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage, |