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:
-rw-r--r--release/scripts/modules/rna_prop_ui.py5
-rw-r--r--release/scripts/startup/bl_operators/wm.py699
2 files changed, 450 insertions, 254 deletions
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):
+ # Retrieve the current type of the custom property on the RNA struct. Some properties like group properties
+ # can be created in the UI, but editing their meta-data isn't supported. In that case, return 'PYTHON'.
+ def _get_property_type(self, item, property_name):
from rna_prop_ui import (
- rna_idprop_ui_prop_update,
rna_idprop_value_item_type,
)
- data_path = self.data_path
- prop = self.property
- prop_escape = bpy.utils.escape_identifier(prop)
-
- prop_old = getattr(self, "_last_prop", [None])[0]
+ prop_value = item[property_name]
- if prop_old is None:
- self.report({'ERROR'}, "Direct execution not supported")
- return {'CANCELLED'}
-
- value_eval, value_failed = self.get_value_eval()
- default_eval, default_failed = self.get_default_eval()
-
- # First remove
- item = eval("context.%s" % data_path)
-
- if (item.id_data and item.id_data.override_library and item.id_data.override_library.reference):
- self.report({'ERROR'}, "Cannot edit properties from override data")
- return {'CANCELLED'}
-
- prop_type_old = type(item[prop_old])
+ prop_type, is_array = rna_idprop_value_item_type(prop_value)
+ if prop_type == int:
+ if is_array:
+ return 'INT_ARRAY'
+ return 'INT'
+ elif prop_type == float:
+ if is_array:
+ return 'FLOAT_ARRAY'
+ return 'FLOAT'
+ elif prop_type == str:
+ if is_array:
+ return 'PYTHON'
+ return 'STRING'
- # Deleting the property will also remove the UI data.
- del item[prop_old]
+ return 'PYTHON'
- # Reassign
- item[prop] = value_eval
- item.property_overridable_library_set('["%s"]' % prop_escape, self.is_overridable_library)
- rna_idprop_ui_prop_update(item, prop)
+ def _init_subtype(self, subtype):
+ subtype = subtype or 'NONE'
+ subtype_items = rna_vector_subtype_items
- self._last_prop[:] = [prop]
+ # Add a temporary enum entry to preserve unknown subtypes
+ if not any(subtype == item[0] for item in subtype_items):
+ subtype_items += ((subtype, subtype, ""),)
- prop_value = item[prop]
- prop_type_new = type(prop_value)
- prop_type, is_array = rna_idprop_value_item_type(prop_value)
+ WM_OT_properties_edit.subtype_items = subtype_items
+ self.subtype = subtype
- if prop_type == int:
- ui_data = item.id_properties_ui(prop)
- if type(default_eval) == str:
- self.report({'WARNING'}, "Could not evaluate number from default value")
- default_eval = None
- elif hasattr(default_eval, "__len__"):
- default_eval = [int(round(value)) for value in default_eval]
+ # Fill the operator's properties with the UI data properties from the existing custom property.
+ # Note that if the UI data doesn't exist yet, the access will create it and use those default values.
+ def _fill_old_ui_data(self, item, name):
+ ui_data = item.id_properties_ui(name)
+ rna_data = ui_data.as_dict()
+
+ if self.property_type in {'FLOAT', 'FLOAT_ARRAY'}:
+ self.min_float = rna_data["min"]
+ self.max_float = rna_data["max"]
+ self.soft_min_float = rna_data["soft_min"]
+ self.soft_max_float = rna_data["soft_max"]
+ self.precision = rna_data["precision"]
+ self.step_float = rna_data["step"]
+ self.subtype = rna_data["subtype"]
+ self.use_soft_limits = (
+ self.min_float != self.soft_min_float or
+ self.max_float != self.soft_max_float
+ )
+ default = self._convert_new_value_array(rna_data["default"], float, 32)
+ self.default_float = default if isinstance(default, list) else [default] * 32
+ elif self.property_type in {'INT', 'INT_ARRAY'}:
+ self.min_int = rna_data["min"]
+ self.max_int = rna_data["max"]
+ self.soft_min_int = rna_data["soft_min"]
+ self.soft_max_int = rna_data["soft_max"]
+ self.step_int = rna_data["step"]
+ self.use_soft_limits = (
+ self.min_int != self.soft_min_int or
+ self.max_int != self.soft_max_int
+ )
+ self.default_int = self._convert_new_value_array(rna_data["default"], int, 32)
+ elif self.property_type == 'STRING':
+ self.default_string = rna_data["default"]
+
+ if self.property_type in { 'FLOAT_ARRAY', 'INT_ARRAY'}:
+ self.array_length = len(item[name])
+
+ # The dictionary does not contain the description if it was empty.
+ self.description = rna_data.get("description", "")
+
+ self._init_subtype(self.subtype)
+ escaped_name = bpy.utils.escape_identifier(name)
+ self.is_overridable_library = bool(item.is_property_overridable_library('["%s"]' % escaped_name))
+
+ # When the operator chooses a different type than the original property,
+ # attempt to convert the old value to the new type for continuity and speed.
+ def _get_converted_value(self, item, name_old, prop_type_new):
+ if prop_type_new == 'INT':
+ return self._convert_new_value_single(item[name_old], int)
+
+ if prop_type_new == 'FLOAT':
+ return self._convert_new_value_single(item[name_old], float)
+
+ if prop_type_new == 'INT_ARRAY':
+ prop_type_old = self._get_property_type(item, name_old)
+ if prop_type_old in {'INT', 'FLOAT', 'INT_ARRAY', 'FLOAT_ARRAY'}:
+ return self._convert_new_value_array(item[name_old], int, self.array_length)
+
+ if prop_type_new == 'FLOAT_ARRAY':
+ prop_type_old = self._get_property_type(item, name_old)
+ if prop_type_old in {'INT', 'FLOAT', 'FLOAT_ARRAY', 'INT_ARRAY'}:
+ return self._convert_new_value_array(item[name_old], float, self.array_length)
+
+ if prop_type_new == 'STRING':
+ return self._convert_old_property_to_string(item, name_old)
+
+ # If all else fails, create an empty string property. That should avoid errors later on anyway.
+ return ""
+
+ # Any time the target type is changed in the dialog, it's helpful to convert the UI data values
+ # to the new type as well, when possible, currently this only applies for floats and ints.
+ def _convert_old_ui_data_to_new_type(self, prop_type_old, prop_type_new):
+ if prop_type_new in {'INT', 'INT_ARRAY'} and prop_type_old in {'FLOAT', 'FLOAT_ARRAY'}:
+ self.min_int = int(self.min_float)
+ self.max_int = int(self.max_float)
+ self.soft_min_int = int(self.soft_min_float)
+ self.soft_max_int = int(self.soft_max_float)
+ self.default_int = self._convert_new_value_array(self.default_float, int, 32)
+ elif prop_type_new in {'FLOAT', 'FLOAT_ARRAY'} and prop_type_old in {'INT', 'INT_ARRAY'}:
+ self.min_float = float(self.min_int)
+ self.max_float = float(self.max_int)
+ self.soft_min_float = float(self.soft_min_int)
+ self.soft_max_float = float(self.soft_max_int)
+ self.default_float = self._convert_new_value_array(self.default_int, float, 32)
+ # Don't convert between string and float/int defaults here, it's not expected like the other conversions.
+
+ # Fill the property's UI data with the values chosen in the operator.
+ def _create_ui_data_for_new_prop(self, item, name, prop_type_new):
+ if prop_type_new in {'INT', 'INT_ARRAY'}:
+ ui_data = item.id_properties_ui(name)
ui_data.update(
- min=int(round(self.min)),
- max=int(round(self.max)),
- soft_min=int(round(self.soft_min)),
- soft_max=int(round(self.soft_max)),
- default=default_eval,
- subtype=self.subtype,
- description=self.description
+ min=self.min_int,
+ max=self.max_int,
+ soft_min=self.soft_min_int if self.use_soft_limits else self.min_int,
+ soft_max=self.soft_max_int if self.use_soft_limits else self.min_int,
+ step=self.step_int,
+ default=self.default_int[0] if prop_type_new == 'INT' else self.default_int[:self.array_length],
+ description=self.description,
)
- elif prop_type == float:
- ui_data = item.id_properties_ui(prop)
- if type(default_eval) == str:
- self.report({'WARNING'}, "Could not evaluate number from default value")
- default_eval = None
+ elif prop_type_new in {'FLOAT', 'FLOAT_ARRAY'}:
+ ui_data = item.id_properties_ui(name)
ui_data.update(
- min=self.min,
- max=self.max,
- soft_min=self.soft_min,
- soft_max=self.soft_max,
- default=default_eval,
+ min=self.min_float,
+ max=self.max_float,
+ soft_min=self.soft_min_float if self.use_soft_limits else self.min_float,
+ soft_max=self.soft_max_float if self.use_soft_limits else self.max_float,
+ step=self.step_float,
+ precision=self.precision,
+ default=self.default_float[0] if prop_type_new == 'FLOAT' else self.default_float[:self.array_length],
+ description=self.description,
subtype=self.subtype,
- description=self.description
)
- elif prop_type == str and not is_array and not default_failed: # String arrays do not support UI data.
- ui_data = item.id_properties_ui(prop)
+ elif prop_type_new == 'STRING':
+ ui_data = item.id_properties_ui(name)
ui_data.update(
- default=self.default,
- subtype=self.subtype,
- description=self.description
+ default=self.default_string,
+ description=self.description,
)
+ escaped_name = bpy.utils.escape_identifier(name)
+ item.property_overridable_library_set('["%s"]' % escaped_name, self.is_overridable_library)
+
+ def _update_blender_for_prop_change(self, context, item, name, prop_type_old, prop_type_new):
+ from rna_prop_ui import (
+ rna_idprop_ui_prop_update,
+ )
+
+ rna_idprop_ui_prop_update(item, name)
+
# If we have changed the type of the property, update its potential anim curves!
if prop_type_old != prop_type_new:
- data_path = '["%s"]' % prop_escape
+ escaped_name = bpy.utils.escape_identifier(name)
+ data_path = '["%s"]' % escaped_name
done = set()
def _update(fcurves):
@@ -1498,149 +1646,196 @@ class WM_OT_properties_edit(Operator):
for nt in adt.nla_tracks:
_update_strips(nt.strips)
- # Otherwise existing buttons which reference freed
- # memory may crash Blender T26510.
- # context.area.tag_redraw()
+ # Otherwise existing buttons which reference freed memory may crash Blender (T26510).
for win in context.window_manager.windows:
for area in win.screen.areas:
area.tag_redraw()
- return {'FINISHED'}
+ def execute(self, context):
+ name_old = getattr(self, "_old_prop_name", [None])[0]
+ if name_old is None:
+ self.report({'ERROR'}, "Direct execution not supported")
+ return {'CANCELLED'}
- def invoke(self, context, _event):
- from rna_prop_ui import (
- rna_idprop_value_to_python,
- rna_idprop_value_item_type
- )
+ data_path = self.data_path
+ name = self.property_name
- prop = self.property
- prop_escape = bpy.utils.escape_identifier(prop)
+ item = eval("context.%s" % data_path)
+ if (item.id_data and item.id_data.override_library and item.id_data.override_library.reference):
+ self.report({'ERROR'}, "Cannot edit properties from override data")
+ return {'CANCELLED'}
- data_path = self.data_path
+ prop_type_old = self._get_property_type(item, name_old)
+ prop_type_new = self.property_type
+ self._old_prop_name[:] = [name]
+
+ if prop_type_new == 'PYTHON':
+ try:
+ new_value = eval(self.eval_string)
+ except Exception as ex:
+ self.report({'WARNING'}, "Python evaluation failed: " + str(ex))
+ return {'CANCELLED'}
+ try:
+ item[name] = new_value
+ except Exception as ex:
+ self.report({'ERROR'}, "Failed to assign value: " + str(ex))
+ return {'CANCELLED'}
+ if name_old != name:
+ del item[name_old]
+ else:
+ new_value = self._get_converted_value(item, name_old, prop_type_new)
+ del item[name_old]
+ item[name] = new_value
+
+ self._create_ui_data_for_new_prop(item, name, prop_type_new)
+ self._update_blender_for_prop_change(context, item, name, prop_type_old, prop_type_new)
+
+ return {'FINISHED'}
+
+ def invoke(self, context, _event):
+ data_path = self.data_path
if not data_path:
self.report({'ERROR'}, "Data path not set")
return {'CANCELLED'}
- self._last_prop = [prop]
+ name = self.property_name
- item = eval("context.%s" % data_path)
+ self._old_prop_name = [name]
+ self.last_property_type = self.property_type
+ item = eval("context.%s" % data_path)
if (item.id_data and item.id_data.override_library and item.id_data.override_library.reference):
- self.report({'ERROR'}, "Cannot edit properties from override data")
+ self.report({'ERROR'}, "Properties from override data can not be edited")
return {'CANCELLED'}
- # retrieve overridable static
- is_overridable = item.is_property_overridable_library('["%s"]' % prop_escape)
- self.is_overridable_library = bool(is_overridable)
-
- # default default value
- value, value_failed = self.get_value_eval()
- prop_type, is_array = rna_idprop_value_item_type(value)
- if prop_type in {int, float}:
- self.default = str(prop_type(0))
- else:
- self.default = ""
-
- # setup defaults
- if prop_type in {int, float}:
- ui_data = item.id_properties_ui(prop)
- rna_data = ui_data.as_dict()
- self.subtype = rna_data["subtype"]
- self.min = rna_data["min"]
- self.max = rna_data["max"]
- self.soft_min = rna_data["soft_min"]
- self.soft_max = rna_data["soft_max"]
- self.use_soft_limits = (
- self.min != self.soft_min or
- self.max != self.soft_max
- )
- self.default = str(rna_data["default"])
- self.description = rna_data.get("description", "")
- elif prop_type == str and not is_array and not value_failed: # String arrays do not support UI data.
- ui_data = item.id_properties_ui(prop)
- rna_data = ui_data.as_dict()
- self.subtype = rna_data["subtype"]
- self.default = str(rna_data["default"])
- self.description = rna_data.get("description", "")
- else:
- self.min = self.soft_min = 0
- self.max = self.soft_max = 1
- self.use_soft_limits = False
- self.description = ""
+ # Set operator's property type with the type of the existing property, to display the right settings.
+ old_type = self._get_property_type(item, name)
+ self.property_type = old_type
- self._init_subtype(prop_type, is_array, self.subtype)
+ # So that the operator can do something for unsupported properties, change the property into
+ # a string, just for editing in the dialog. When the operator executes, it will be converted back
+ # into a python value. Always do this conversion, in case the Python property edit type is selected.
+ self.eval_string = self._convert_old_property_to_string(item, name)
- # store for comparison
- self._cmp_props = self._cmp_props_get()
+ if old_type != 'PYTHON':
+ self._fill_old_ui_data(item, name)
wm = context.window_manager
return wm.invoke_props_dialog(self)
- def check(self, _context):
- cmp_props = self._cmp_props_get()
+ def check(self, context):
changed = False
- if self._cmp_props != cmp_props:
- if cmp_props["use_soft_limits"]:
- if cmp_props["soft_range"] != self._cmp_props["soft_range"]:
- self.min = min(self.min, self.soft_min)
- self.max = max(self.max, self.soft_max)
+
+ # In order to convert UI data between types for type changes before the operator has actually executed,
+ # compare against the type the last time the check method was called (the last time a value was edited).
+ if self.property_type != self.last_property_type:
+ self._convert_old_ui_data_to_new_type(self.last_property_type, self.property_type)
+ changed = True
+
+ # Make sure that min is less than max, soft range is inside hard range, etc.
+ if self.property_type in {'FLOAT', 'FLOAT_ARRAY'}:
+ if self.min_float > self.max_float:
+ self.min_float, self.max_float = self.max_float, self.min_float
+ changed = True
+ if self.soft_min_float > self.soft_max_float:
+ self.soft_min_float, self.soft_max_float = self.soft_max_float, self.soft_min_float
+ changed = True
+ if self.use_soft_limits:
+ if self.soft_max_float > self.max_float:
+ self.soft_max_float = self.max_float
changed = True
- if cmp_props["hard_range"] != self._cmp_props["hard_range"]:
- self.soft_min = max(self.min, self.soft_min)
- self.soft_max = min(self.max, self.soft_max)
+ if self.soft_min_float < self.min_float:
+ self.soft_min_float = self.min_float
changed = True
- else:
- if cmp_props["soft_range"] != cmp_props["hard_range"]:
- self.soft_min = self.min
- self.soft_max = self.max
+ elif self.property_type in {'INT', 'INT_ARRAY'}:
+ if self.min_int > self.max_int:
+ self.min_int, self.max_int = self.max_int, self.min_int
+ changed = True
+ if self.soft_min_int > self.soft_max_int:
+ self.soft_min_int, self.soft_max_int = self.soft_max_int, self.soft_min_int
+ changed = True
+ if self.use_soft_limits:
+ if self.soft_max_int > self.max_int:
+ self.soft_max_int = self.max_int
+ changed = True
+ if self.soft_min_int < self.min_int:
+ self.soft_min_int = self.min_int
changed = True
- changed |= (cmp_props["use_soft_limits"] != self._cmp_props["use_soft_limits"])
-
- if changed:
- cmp_props = self._cmp_props_get()
-
- self._cmp_props = cmp_props
+ self.last_property_type = self.property_type
return changed
def draw(self, _context):
- from rna_prop_ui import (
- rna_idprop_value_item_type,
- )
-
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
- layout.prop(self, "property")
- layout.prop(self, "value")
+ layout.prop(self, "property_type")
+ layout.prop(self, "property_name")
- value, value_failed = self.get_value_eval()
- proptype, is_array = rna_idprop_value_item_type(value)
+ if self.property_type in {'FLOAT', 'FLOAT_ARRAY'}:
+ if self.property_type == 'FLOAT_ARRAY':
+ layout.prop(self, "array_length")
+ col = layout.column(align=True)
+ col.prop(self, "default_float", index=0, text="Default")
+ for i in range(1, self.array_length):
+ col.prop(self, "default_float", index=i, text=" ")
+ else:
+ layout.prop(self, "default_float", index=0)
+
+ col = layout.column(align=True)
+ col.prop(self, "min_float")
+ col.prop(self, "max_float")
+
+ col = layout.column()
+ col.prop(self, "is_overridable_library")
+ col.prop(self, "use_soft_limits")
+
+ col = layout.column(align=True)
+ col.enabled = self.use_soft_limits
+ col.prop(self, "soft_min_float", text="Soft Min")
+ col.prop(self, "soft_max_float", text="Max")
+
+ layout.prop(self, "step_float")
+ layout.prop(self, "precision")
+
+ # Subtype is only supported for float properties currently.
+ if self.property_type != 'FLOAT':
+ layout.prop(self, "subtype")
+ elif self.property_type in {'INT', 'INT_ARRAY'}:
+ if self.property_type == 'INT_ARRAY':
+ layout.prop(self, "array_length")
+ col = layout.column(align=True)
+ col.prop(self, "default_int", index=0, text="Default")
+ for i in range(1, self.array_length):
+ col.prop(self, "default_int", index=i, text=" ")
+ else:
+ layout.prop(self, "default_int", index=0)
- row = layout.row()
- row.enabled = proptype in {int, float, str}
- row.prop(self, "default")
+ col = layout.column(align=True)
+ col.prop(self, "min_int")
+ col.prop(self, "max_int")
- col = layout.column(align=True)
- col.prop(self, "min")
- col.prop(self, "max")
+ col = layout.column()
+ col.prop(self, "is_overridable_library")
+ col.prop(self, "use_soft_limits")
- col = layout.column()
- col.prop(self, "is_overridable_library")
- col.prop(self, "use_soft_limits")
+ col = layout.column(align=True)
+ col.enabled = self.use_soft_limits
+ col.prop(self, "soft_min_int", text="Soft Min")
+ col.prop(self, "soft_max_int", text="Max")
- col = layout.column(align=True)
- col.enabled = self.use_soft_limits
- col.prop(self, "soft_min", text="Soft Min")
- col.prop(self, "soft_max", text="Max")
- layout.prop(self, "description")
+ layout.prop(self, "step_int")
+ elif self.property_type == 'STRING':
+ layout.prop(self, "default_string")
- if is_array and proptype == float:
- layout.prop(self, "subtype")
+ if self.property_type == 'PYTHON':
+ layout.prop(self, "eval_string")
+ else:
+ layout.prop(self, "description")
class WM_OT_properties_add(Operator):
@@ -1706,7 +1901,7 @@ class WM_OT_properties_remove(Operator):
bl_options = {'UNDO', 'INTERNAL'}
data_path: rna_path
- property: rna_custom_property
+ property_name: rna_custom_property_name
def execute(self, context):
from rna_prop_ui import (
@@ -1719,9 +1914,9 @@ class WM_OT_properties_remove(Operator):
self.report({'ERROR'}, "Cannot remove properties from override data")
return {'CANCELLED'}
- prop = self.property
- rna_idprop_ui_prop_update(item, prop)
- del item[prop]
+ name = self.property_name
+ rna_idprop_ui_prop_update(item, name)
+ del item[name]
return {'FINISHED'}