[Bf-blender-cvs] [bf948b2cef3] master: Custom Properties: Rewrite edit operator, improve UX

Hans Goudey noreply at git.blender.org
Thu Sep 23 04:57:50 CEST 2021


Commit: bf948b2cef3ba340a6bba5e7bd7f4911c9a9275a
Author: Hans Goudey
Date:   Wed Sep 22 21:56:54 2021 -0500
Branches: master
https://developer.blender.org/rBbf948b2cef3ba340a6bba5e7bd7f4911c9a9275a

Custom Properties: Rewrite edit operator, improve UX

This commit changes the custom property edit operator to make editing
different properties types more obvious and expose more of the data,
made more easily possible by the recent UI data refactor.

Previously, the operator guessed the type you wanted based on what you
wrote in a text box. That was problematic, you couldn't make a string
property with a value of `1234`, and you had to know about the Python
syntax for lists in order to create an array property. It was also slow
and error prone; it was too easy to make a typo.

Improvements compared to the old operator:
 - A type drop-down to choose between the property types.
 - Step and precision values are exposed.
 - Buttons that have the correct type based on the property.
 - String properties no longer display min, max, etc. buttons.
 - Generally works in more cases. The old operator tended to break.
 - Choose array length with a slider.
 - Easy to choose to use python evaluation when necessary.
 - Code is commented, split up, and much easier to understand.

The custom property's value is purposefully not exposed, since the Edit
operator is for changing the property's metadata now, rather than the
value itself. Though in the "Python" mode the value is still available.

More improvements are possible in the future, like exposing different
subtypes, and improving the UI of the custom properties panel.

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

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

M	release/scripts/modules/rna_prop_ui.py
M	release/scripts/startup/bl_operators/wm.py

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

diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 26a2f9ad89b..6d92c94a85c 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -21,9 +21,10 @@
 import bpy
 
 from mathutils import Vector
+from bpy.types import bpy_prop_array
 from idprop.types import IDPropertyArray, IDPropertyGroup
 
-ARRAY_TYPES = (list, tuple, IDPropertyArray, Vector)
+ARRAY_TYPES = (list, tuple, IDPropertyArray, Vector, bpy_prop_array)
 
 # Maximum length of an array property for which a multi-line
 # edit field will be displayed in the Custom Properties panel.
@@ -136,7 +137,7 @@ def draw(layout, context, context_member, property_type, *, use_edit=True):
 
     def assign_props(prop, val, key):
         prop.data_path = context_member
-        prop.property = key
+        prop.property_name = key
 
         try:
             prop.value = str(val)
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index ebf80ca9ee4..6bf45cc5a15 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -23,6 +23,7 @@ import bpy
 from bpy.types import (
     Menu,
     Operator,
+    bpy_prop_array,
 )
 from bpy.props import (
     BoolProperty,
@@ -31,6 +32,8 @@ from bpy.props import (
     FloatProperty,
     IntProperty,
     StringProperty,
+    IntVectorProperty,
+    FloatVectorProperty,
 )
 from bpy.app.translations import pgettext_iface as iface_
 
@@ -1266,48 +1269,20 @@ rna_path = StringProperty(
     options={'HIDDEN'},
 )
 
-rna_value = StringProperty(
-    name="Property Value",
-    description="Property value edit",
-    maxlen=1024,
-)
-
-rna_default = StringProperty(
-    name="Default Value",
-    description="Default value of the property. Important for NLA mixing",
-    maxlen=1024,
-)
-
-rna_custom_property = StringProperty(
+rna_custom_property_name = StringProperty(
     name="Property Name",
     description="Property name edit",
     # Match `MAX_IDPROP_NAME - 1` in Blender's source.
     maxlen=63,
 )
 
-rna_min = FloatProperty(
-    name="Min",
-    description="Minimum value of the property",
-    default=-10000.0,
-    precision=3,
-)
-
-rna_max = FloatProperty(
-    name="Max",
-    description="Maximum value of the property",
-    default=10000.0,
-    precision=3,
-)
-
-rna_use_soft_limits = BoolProperty(
-    name="Use Soft Limits",
-    description="Limits the Property Value slider to a range, values outside the range must be inputted numerically",
-)
-
-rna_is_overridable_library = BoolProperty(
-    name="Is Library Overridable",
-    description="Allow the property to be overridden when the data-block is linked",
-    default=False,
+rna_custom_property_type_items = (
+    ('FLOAT', "Float", "A single floating-point value"),
+    ('FLOAT_ARRAY', "Float Array", "An array of floating-point values"),
+    ('INT', "Integer", "A single integer"),
+    ('INT_ARRAY', "Integer Array", "An array of integers"),
+    ('STRING', "String", "A string value"),
+    ('PYTHON', "Python", "Edit a python value directly, for unsupported property types"),
 )
 
 # Most useful entries of rna_enum_property_subtype_items for number arrays:
@@ -1319,160 +1294,333 @@ rna_vector_subtype_items = (
     ('QUATERNION', "Quaternion Rotation", "Quaternion rotation (affects NLA blending)"),
 )
 
-
 class WM_OT_properties_edit(Operator):
-    """Edit the attributes of the property"""
+    """Change a custom property's type, or adjust how it is displayed in the interface"""
     bl_idname = "wm.properties_edit"
     bl_label = "Edit Property"
     # register only because invoke_props_popup requires.
     bl_options = {'REGISTER', 'INTERNAL'}
 
+    # Common settings used for all property types. Generally, separate properties are used for each
+    # type to improve the experience when choosing UI data values.
+
     data_path: rna_path
-    property: rna_custom_property
-    value: rna_value
-    default: rna_default
-    min: rna_min
-    max: rna_max
-    use_soft_limits: rna_use_soft_limits
-    is_overridable_library: rna_is_overridable_library
-    soft_min: rna_min
-    soft_max: rna_max
+    property_name: rna_custom_property_name
+    property_type: EnumProperty(
+        name="Type",
+        items=lambda self, _context: WM_OT_properties_edit.type_items,
+    )
+    is_overridable_library: BoolProperty(
+        name="Is Library Overridable",
+        description="Allow the property to be overridden when the data-block is linked",
+        default=False,
+    )
     description: StringProperty(
-        name="Tooltip",
+        name="Description",
+    )
+
+    # Shared for integer and string properties.
+
+    use_soft_limits: BoolProperty(
+        name="Use Soft Limits",
+        description="Limits the Property Value slider to a range, values outside the range must be inputted numerically",
+    )
+    array_length: IntProperty(
+        name="Array Length",
+        default=3,
+        min=1,
+        max=32, # 32 is the maximum size for RNA array properties.
+    )
+
+    # Integer properties.
+
+    # This property stores values for both array and non-array properties.
+    default_int: IntVectorProperty(
+        name="Default Value",
+        size=32,
+    )
+    min_int: IntProperty(
+        name="Min",
+        default=-10000,
+    )
+    max_int: IntProperty(
+        name="Max",
+        default=10000,
+    )
+    soft_min_int: IntProperty(
+        name="Soft Min",
+        default=-10000,
+    )
+    soft_max_int: IntProperty(
+        name="Soft Max",
+        default=10000,
+    )
+    step_int: IntProperty(
+        name="Step",
+        min=1,
+        default=1,
+    )
+
+    # Float properties.
+
+    # This property stores values for both array and non-array properties.
+    default_float: FloatVectorProperty(
+        name="Default Value",
+        size=32,
+    )
+    min_float: FloatProperty(
+        name="Min",
+        default=-10000.0,
+    )
+    max_float: FloatProperty(
+        name="Max",
+        default=-10000.0,
+    )
+    soft_min_float: FloatProperty(
+        name="Soft Min",
+        default=-10000.0,
+    )
+    soft_max_float: FloatProperty(
+        name="Soft Max",
+        default=-10000.0,
+    )
+    precision: IntProperty(
+        name="Precision",
+        default=3,
+        min=0,
+        max=8,
+    )
+    step_float: FloatProperty(
+        name="Step",
+        default=0.1,
+        min=0.001,
     )
     subtype: EnumProperty(
         name="Subtype",
         items=lambda self, _context: WM_OT_properties_edit.subtype_items,
     )
 
-    subtype_items = rna_vector_subtype_items
-
-    def _init_subtype(self, prop_type, is_array, subtype):
-        subtype = subtype or 'NONE'
-        subtype_items = rna_vector_subtype_items
+    # String properties.
 
-        # Add a temporary enum entry to preserve unknown subtypes
-        if not any(subtype == item[0] for item in subtype_items):
-            subtype_items += ((subtype, subtype, ""),)
+    default_string: StringProperty(
+        name="Default Value",
+        maxlen=1024,
+    )
 
-        WM_OT_properties_edit.subtype_items = subtype_items
-        self.subtype = subtype
+    # Store the value converted to a string as a fallback for otherwise unsupported types.
+    eval_string: StringProperty(
+        name="Value",
+        description="Python value for unsupported custom property types"
+    )
 
-    def _cmp_props_get(self):
-        # Changing these properties will refresh the UI
-        return {
-            "use_soft_limits": self.use_soft_limits,
-            "soft_range": (self.soft_min, self.soft_max),
-            "hard_range": (self.min, self.max),
-        }
+    type_items = rna_custom_property_type_items
+    subtype_items = rna_vector_subtype_items
 
-    def get_value_eval(self):
-        failed = False
-        try:
-            value_eval = eval(self.value)
-            # assert else None -> None, not "None", see T33431.
-            assert(type(value_eval) in {str, float, int, bool, tuple, list})
-        except:
-            failed = True
-            value_eval = self.value
+    # Helper method to avoid repetative code to retrieve a single value from sequences and non-sequences.
+    @staticmethod
+    def _convert_new_value_single(old_value, new_type):
+        if hasattr(old_value, "__len__"):
+            return new_type(old_value[0])
+        return new_type(old_value)
 
-        return value_eval, failed
+    # Helper method to create a list of a given value and type, using a sequence or non-sequence old value.
+    @staticmethod
+    def _convert_new_value_array(old_value, new_type, new_len):
+        if hasattr(old_value, "__len__"):
+            new_array = [new_type()] * new_len
+            for i in range(min(len(old_value), new_len)):
+                new_array[i] = new_type(old_value[i])
+            return new_array
+        return [new_type(old_value)] * new_len
+
+    # Convert an old property for a string, avoiding unhelpful string representations for custom list types.
+    @staticmethod
+    def _convert_old_property_to_string(item, name):
+        # The IDProperty group view API currently doesn't have a "lookup" method.
+        for key, value in item.items():
+            if key == name:
+                old_value = value
+                break
 
-    def get_default_eval(self):
-        failed = False
-        try:
-            default_eval = eval(self.default)
-            # assert else None -> None, not "None", see T33431.
-            assert(type(default_eval) in {str, float, int, bool, tuple, list})
-        except:
-            failed = True
-            default_eval = self.default
+        # In order to get a better string conversion, convert the property to a builtin sequence type first.
+        to_dict = getattr(old_value, "to_dict", None)
+        to_list = getattr(old_value, "to_list", None)
+        if to_dict:
+            old_value = to_dict()
+        elif to_list:
+            old_value = to_list()
 
-        return default_eval, failed
+        return str(old_value)
 
-    def execute(self, context):
+    # Retriev

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list