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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2018-12-15 22:37:12 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2018-12-19 14:20:35 +0300
commit61c941f040d367d18fcaa57c9e8e0c2078193d97 (patch)
tree9cf843e4f19fffda991afb77595ec4d287a0b142 /release
parent908a2742403b279cd6dfa5c27acb76d68d3f1523 (diff)
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
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/rna_prop_ui.py19
-rw-r--r--release/scripts/startup/bl_operators/object.py44
-rw-r--r--release/scripts/startup/bl_operators/wm.py55
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py5
4 files changed, 117 insertions, 6 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"