Clickable controls in Maya

Is there a better way to have clickable controls on a character rig in Maya? I’m currently using script jobs, which are a bit slow and messy. For example I want a button to nudge a foot controller closer or further away from the hips.

Clickable as in the actual event of the user pressing the mouse button triggers a specific code function, not really. You could do it with a dummy enum attribute and a callback that triggers the code and resets the attribute; however I would sooner make sure that the interaction method itself of clicking is the best for the user to accomplish the task.
Inherently this is a restricted (restrictive) way of interacting with the rig. For this example, would it not be better to connect the foot control offset to a slider, either in the attribute editor or in space, to give the user a finer degree of control? Obviously anything like this that can leverage continuous connection will also be massively faster, more stable, etc
Honestly the only use I’ve found for mouse interaction is with custom marking menus, where there may be many different options for the user to select (ie space switches).

1 Like

For simple button-style functionality you can use the buttonManip command to make a clickable object in the scene that will trigger a script. It works, but the UI is not something everybody loves – the big issue is getting the visible object to have an appropriate scale in 3d views.

An alternative would be to add scriptNodes to your clickable objects. You’d have to add a custom attribute to your node and connect up the script node to it, then add a scriptJob to run the script when the object is selected. Here’s an ultra-simplified example:

import maya.cmds as cmds 

sphere, _ = cmds.polySphere()

# attribute to track the script node
cmds.addAttr(sphere, ln='script', at='message')

# make a script node, make sure it's python
script = cmds.scriptNode(bs = 'print "hello world"')
cmds.setAttr(script + '.sourceType', 1)

# connect it to the object
cmds.connectAttr(script + '.message', sphere + '.script')


# run this on selection changes -- if the first selected item
# has a script node connection, execute it
def run_selected():
    clicked = (cmds.ls(sl=1) or [None])[0]
    if clicked:
        try:
            node = cmds.listConnections(clicked + '.script')
        except:
            return
        cmds.scriptNode(node, eb=True)
        
                
                
cmds.scriptJob(e= ('SelectionChanged', run_selected))
3 Likes

That’s an awesome tool! Never knew about those

Hi, thanks for your tip. But then, how do I do If I want this behavior to stay active
in my file? (As if it was a MEL expression)

Thanks

If you are talking about @Theodox’s anser, you can replace the line

script = cmds.scriptNode(bs = 'print "hello world"')

The argument bs will take functions.

script = cmds.scriptNode(bs = 'exempleFunction()')

def exempleFunction():
....print('hello')