0
$\begingroup$

This might just not be possible but I thought I'd ask. Is it possible to have two sliders min=0.0, max=1.0. Where their contents always sum to 1 but the user can still move them.

For example a slider A and slider B. When A is increased, B decreases by some linearly proportional amount.

I tried a couple different approaches, first by just setting the value in draw:

total = myPropGroup.probA + myPropGroup.probB
if total > 1.0:
   myPropGroup.probA = myPropGroup.probA / total
   myPropGroup.probB = myPropGroup.probB / total
layoutBox.prop(myPropGroup, "probA", text="Probability A", slider=True)
layoutBox.prop(myPropGroup, "probB", text="Probability B", slider=True)

Didn't even load.

I also tried using the set and update functions of the properties but caused some infinite loops.

$\endgroup$
1
  • $\begingroup$ You'll want to use an update function on your properties. a similar instance of comparing one property to another is here. $\endgroup$
    – Ratt
    Commented Jan 24, 2023 at 20:00

1 Answer 1

2
$\begingroup$

Rough example.

Honestly a single variable could be used as a property and just subtract the value from 1 for any comparison.

import bpy


def upd_left(self, context):
    if not self.my_prop_right + self.my_prop_left == 1:
        self.my_prop_right = 1 - self.my_prop_left


def upd_right(self, context):
    if not self.my_prop_right + self.my_prop_left == 1:
        self.my_prop_left = 1 - self.my_prop_right


class TEST_PG_props(bpy.types.PropertyGroup):
    my_prop_left: bpy.props.FloatProperty(
        name="my_prop_left",
        default=0,
        min=0,
        max=1,
        update=upd_left,
        )

    my_prop_right: bpy.props.FloatProperty(
        name="my_prop_right",
        default=0,
        min=0,
        max=1,
        update=upd_right,
        )


class TEST_PT_test_panel(bpy.types.Panel):
    bl_idname = "TEST_PT_test_panel"
    bl_label = "Test Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Test Tab"
 
    def draw(self, context):
        my_props = context.scene.my_props
        layout = self.layout
        row = layout.row()
        row.prop(my_props, "my_prop_left", text="left")
        row.prop(my_props, "my_prop_right", text="right")


classes = [
    TEST_PG_props,
    TEST_PT_test_panel,
    ]


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.my_props = bpy.props.PointerProperty(
            type=TEST_PG_props)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.my_props

if __name__ == "__main__":
    register()
```
$\endgroup$
2
  • $\begingroup$ This is better than diving by the sum because the property you're editing is set exactly and won't jump around. But instead of the if to avoid infinite recursion, you can set the underlying custom prop which won't invoke update again: self["my_prop_right"] = 1 - self.my_prop_left. $\endgroup$
    – scurest
    Commented Jan 24, 2023 at 20:29
  • 1
    $\begingroup$ @scurest thanks for the info on using self["my_prop_right"] to avoid recursion. I was unaware of that functionality and while it Likely would be a better implementation I think I will leave the answer as is for clarity of avoiding recursion. Hopefuly anyone that finds this post in the future will read your comment and make their own decision on best implementation for their needs. $\endgroup$
    – Ratt
    Commented Jan 24, 2023 at 21:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .