Creating a slider for x location of a bone. And a menu for space switching.

A newbie question I know, but I’m stuck on it. What I’m trying to do is create a UI slider to control a bones x location (which drives some constraints on other bones). Here’s what I have at the moment:

row.prop(pose_bones["UI-Slider.SpineSpline"], "location", text = "Spine Spline" , slider = True)

pose_bones is just a list of the bones in the armature. It works, but I end up with tiny sliders for each of the x y and z co-ords of the bone and I only want to control the x location. I tried “location[0]” but that doesnt work.

Preferably if I could set the min and max values of the slider too that would be great.

EDIT: I have another question as well, I thought I’d tack it on. I’m trying to add an enum property to a bone so I can switch between different child of constraints using the value of the enum property as a driver. However I cant work out how to add such a property to a bone.

What I’d like to do is have a drop down menu in my UI where the user can switch between head space, body space and world space for aligning the IK hand constraints.

Here is what I have so far for the second problem based on http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Properties, taking apart the riggify scripts, and trawling through the API docs, but it still doesn’t work.


### Add properties for space switching. ###

#Define enum property for bones
handbones = [bpy.data.objects['RIG_Sheriff'].pose.bones['IK-Hand.L'],bpy.data.objects['RIG_Sheriff'].pose.bones['IK-Hand.R']]

def initBoneProperties(bone):
    bpy.types.Bone.ssenum = EnumProperty(
        items = [('World', 'World', 'World'), 
                ('Body', 'Body', 'Body'), 
                ('Head', 'Head', 'Head')],
        name = "space_switch_enum")
    bone['ssenum'] = 0
    
for bone in handbones:
    initBoneProperties(bone)

###Rig Properties UI###

class RigUI(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Rig Main Properties"
    bl_idname = rig_id + "_PT_rig_ui"

    @classmethod
    def poll(self, context):
        if context.mode != 'POSE':
            return False
        try:
            return (context.active_object.data.get("rig_id") == rig_id)
        except (AttributeError, KeyError, TypeError):
            return False
        
    def draw(self, context):
        layout = self.layout
        pose_bones = bpy.context.active_object.pose.bones
        try:
            selected_bones = [bone.name for bone in context.selected_pose_bones]
            selected_bones += [context.active_pose_bone.name]
        except (AttributeError, TypeError):
            return

        def is_selected(names):
            # Returns whether any of the named bones are selected.
            if type(names) == list:
                for name in names:
                    if name in selected_bones:
                        return True
            elif names in selected_bones:
                return True
            return False

        hands = ["IK-Hand.L","IK-Hand.R"]
        if is_selected(hands[0]):
            layout.prop(pose_bones["IK-Hand.L"], '["ssenum"]', text = "Hand Space")
        if is_selected(hands[1]):
            layout.prop(pose_bones["IK-Hand.R"], '["ssenum"]', text = "Hand Space")

Aha solved the space switching bit. I didn’t realise you can use enum type properties for RNA properties.

This creates a poperty I can then access with [bone].ss_type

space_switch_type = bpy.props.EnumProperty(name = "Space Switch Type",
        items = (('world', "World", "World Space"),
            ('body', "Body", "Body Space"),
            ('head', "Head", "Head Space")),
        description = "Parent space for hands",
        default = 'body')

bpy.types.PoseBone.ss_type = space_switch_type
rig.pose.bones['IK-Hand.L'].ss_type = 'world'
rig.pose.bones['IK-Hand.R'].ss_type = 'world'

Still no joy on the x slider front though.

Aha cracked the other one too. Added index = 0 to the layout.prop line.

class RigSliders(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Sliders"
    bl_idname = rig_id + "_PT_rig_sliders"
    
    @classmethod
    def poll(self, context):
        if context.mode != 'POSE':
            return False
        try:
            return (context.active_object.data.get("rig_id") == rig_id)
        except (AttributeError, KeyError, TypeError):
            return False
        
    def draw(self, context):
        layout = self.layout
        col = layout.column()
        pose_bones = bpy.context.active_object.pose.bones
        
        row = col.row()       
        row.prop(pose_bones["UI-Slider.SpineSpline"], 'location', index = 0, text = "Spine Spline", slider = True)

Only trouble is that now I have a slider that goes from -10000 to 10000. Not so useful for a bone I want to move from 0 to 0.4. Any ideas?

try something like this…


row.prop(pose_bones["UI-Slider.SpineSpline"], 'location', index = 0, text = "Spine Spline", slider = True, min = 0, max = 4)

#

Doesn’t work for me I’m afraid:

TypeError: UILayout.prop(): was called with invalid keyword arguments(s) (max, min), expected (data, property, text, icon, expand, slider, toggle, icon_only, event, full_event, emboss, index)

sorry, I’m not into rigging…
edit: just tried and understood your problem, I would define a new prop and show it in the panel, not the real position of object but this prop, and use it to drive the bones… maybe using the new update option as this is the way I use panels and props… but again, not really into this stuff :expressionless:

Wish I could help…but had exactly the same problem with getting just the x-scale…thanks for posting your solutions and not just asking about your problems! Been stuck on that problem the whole day yesterday!!! :smiley:

@liero: The trouble is if I make it a driver I won’t be able to move the bone manually in the viewport anymore. If I can work out how to make a nice slider for the x location property though then the animator has the choice of moving the bone or using a slider.

If I have to go down the route of creating properties, I might as well just control the drivers that the x location of the bone affects with the property itself instead.

I’ve decided to go for a property based solution instead. Sliders only, no bones.

Just to let you know, removing the ‘slider=True’ from the location prop will result in a much more responsive slider -it feels like in the original gui- try both and see…
The ‘slider=True’ makes it very difficult to work on small values, it totally changes prop’s behaviour (unless you use your own, with min and max values, it works great there)