I'm displaying N-instances of a Collection Property (depending on the amount of selected objects) — the values are floats, default values are 100/N
, and I want to be able to recalculate values of other properties when one of the instance is changed so that a sum would be always 100 — basically I want to have something like influence between objects limited by 100(%).
Here's how it looks: in this example two other fields should be 25
and 25
I tried to use the update function and change "other values" (instances that aren't the active) but I guess since every instance uses the same function Blender goes in infinite recursion and crashes. Maybe my approach is wrong and I should do this in a different way?
import bpy
import math
def update_float(self,context):
other_props = [prop for prop in context.scene.my_custom_set if prop.name != self.name]
rest = 100 - self.value
for prop in other_props:
prop.value = rest / len(context.selected_objects) # crashes blender
class SceneSettingItem(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(name="Obj Name", default="")
value: bpy.props.FloatProperty(name="Z coord", default=0, max=100, min=0, update=update_float)
class SimpleOperator2(bpy.types.Operator):
""""""
bl_idname = "object.simple_operator_sk"
bl_label = "Collection Property Test 2"
bl_options = {'REGISTER', 'UNDO'}
def draw(self, context):
layout = self.layout
for my_item in context.scene.my_custom_set:
row = layout.row()
row.prop(my_item, "value", text=f"Prop for {my_item.name}")
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
context.scene.my_custom_set.clear()
for ob in context.selected_objects:
my_item = context.scene.my_custom_set.add()
my_item.name = ob.name
my_item.value = math.ceil(
10000 / len(context.selected_objects))/100
return context.window_manager.invoke_props_dialog(self)
def register():
bpy.utils.register_class(SimpleOperator2)
bpy.utils.register_class(SceneSettingItem)
bpy.types.Scene.my_custom_set = bpy.props.CollectionProperty(type=SceneSettingItem)
def unregister():
del bpy.types.Scene.my_custom_set
bpy.utils.unregister_class(SimpleOperator2)
bpy.utils.unregister_class(SceneSettingItem)
if __name__ == "__main__":
register()