[Bf-blender-cvs] [61c941f040d] blender2.8: RNA: support setting default values for custom properties.

Alexander Gavrilov noreply at git.blender.org
Wed Dec 19 12:21:10 CET 2018


Commit: 61c941f040d367d18fcaa57c9e8e0c2078193d97
Author: Alexander Gavrilov
Date:   Sat Dec 15 22:37:12 2018 +0300
Branches: blender2.8
https://developer.blender.org/rB61c941f040d367d18fcaa57c9e8e0c2078193d97

RNA: support setting default values for custom properties.

NLA requires a usable default value for all properties that
are to be animated via it, without any exceptions. This is
the real cause of T36496: using the default of 0 for a scale
related custom property obviously doesn't work.

Thus, to really fix this it is necessary to support configurable
default values for custom properties, which are very frequently
used in rigs for auxiliary settings. For common use it is enough
to support this for scalar float and integer properties.

The default can be set via the custom property configuration
popup, or a right click menu option. In addition, to help in
updating old rigs, an operator that saves current values as
defaults for all object and bone properties is added.

Reviewers: campbellbarton, brecht

Differential Revision: https://developer.blender.org/D4084

===================================================================

M	release/scripts/modules/rna_prop_ui.py
M	release/scripts/startup/bl_operators/object.py
M	release/scripts/startup/bl_operators/wm.py
M	release/scripts/startup/bl_ui/space_view3d.py
M	source/blender/editors/interface/interface_context_menu.c
M	source/blender/editors/interface/interface_ops.c
M	source/blender/makesrna/RNA_access.h
M	source/blender/makesrna/intern/rna_access.c

===================================================================

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_IN

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list