PyMEL: Enumeration problem when creating menuItems


#1
from functools import partial

# Creates menu items of the UV sets in a selection, with the active set marked with a checkbox
def buildUVSetMenu(parentUI, editor):

    # Internal func used by functools.partial for creating menu items
    def createMenuItemCmd(uvSet, uvSetIndex=0, cBoxState=False):       
        pm.menuItem(
            checkBox=cBoxState,
            command=lambda *args: pm.textureWindow(editor, setUvSet=uvSetIndex),
            enableCommandRepeat=True,
            label=uvSet,
            parent=parentUI,
        )
        
    # Delete popup menu contents
    pm.menu(parentUI, edit=True, deleteAllItems=True)

    # Mesh or components selected?
    sel = pm.filterExpand( selectionMask=(12, 31, 32, 34, 35) )    
    if sel != [] and sel != None:

        # Get UV sets
        uvSetsAll, uvSetCurrent = getSetsFunc() # Returns list of all UV sets as well as the current UV set
        if uvSetsAll != [] and uvSetsAll != None:
        
            cBoxStateList = [] # List of checkbox states (bools)
            menuItemList = [] # List of partial funcs

            # Create list of partials
            for item in uvSetsAll: 
            
                # Check UV set for instance identifiers
                uvSetPerInst = pm.polyUVSet(
                    sel, query=True,
                        perInstance=True,
                        uvSet=item,
                )
                
                # If instance identifier was found, continue to next uv-set in the loop
                if uvSetPerInst == None:
                    continue
                else:
                    uvSetInst = uvSetPerInst[0]

                # Is the item in the loop the current set?
                cBoxState = (uvSetCurrent[0] == item) # getSetsFunc() returns two lists - this is a bug so we use uvSetCurrent[0] for now
                cBoxStateList.append(cBoxState)             
             
                # Append to list of function commands
                menuItemList.append(partial(createMenuItemCmd, uvSetInst))
            
            # Create the menu items. This is where things get wrong. 
            for x,y,uvSetCurrent in enumerate(menuItemList): uvSetCurrent(x,cBoxStateList[y])

    else: # No uv sets found
        pm.menuItem(
            enable=False, 
            enableCommandRepeat=False, 
            label="No object selected.",
            )

What I want to do is to create X amount of menuItems (determined by the amount of UV-sets on a selection), add a checkbox to the menu item with the current/active set, and finally have the command of said menu items so that I can set the active UV-set via the menu. (ie: menu item 2 will make UV set two the active set). It’s late and I’m probably doing some obvious thing incorrectly here so please help me out. Thanks in advance.


#2

Did you forget to post the error message? Or to explain what the problem is? Or is it that comment in your code about the bug?

Ah hang on… is it this…

for x,y,uvSetCurrent in enumerate(menuItemList)

that looks strange to me. Maybe…

for i,menuItem in enumerate(menuItemList)

then expand it.

David


#3

Can you tell us where your script fails?


#4

Oh yes, sorry.
It fails when the menu pops up. The buildUVSetMenu -function called by the postMenuCommand off a menu, like this:

pm.menu(
        theMenu, edit=True, 
            postMenuCommand=lambda *args: buildUVSetMenu (theMenu, editor)
        )

ValueError: need more than 2 values to unpack

Maybe this could bring more clarity to my issues.
I previously thought that lambda functions takes the value you pass them but what you pass is a pointer to variable. So this is how I thought I would create these menu items before before I looked at functools.partial.

# Creates menu items of the UV sets in a selection, with the active set marked with a checkbox
def buildUVSetMenu(parentUI):
 
    # Delete popup menu contents
    pm.menu(parentUI, edit=True, deleteAllItems=True)

    # Mesh or components selected?
    sel = pm.filterExpand( selectionMask=(12, 31, 32, 34, 35) )    
    if sel != [] and sel != None:

        # Get UV sets
        uvSetsAll, uvSetCurrent = getSetsFunc() # Returns list of all UV sets as well as the current UV set
        if uvSetsAll != [] and uvSetsAll != None:

            # Create list of partials
            for item in uvSetsAll: 
            
                # Check UV set for instance identifiers
                uvSetPerInst = pm.polyUVSet(
                    sel, query=True,
                        perInstance=True,
                        uvSet=item,
                )
                
                # If instance identifier was found, continue to next uv-set in the loop
                if uvSetPerInst == None:
                    continue
                else:
                    uvSetInst = uvSetPerInst[0]

                # Is the item in the loop the current set?
                cBoxState = (uvSetCurrent[0] == item) # getSetsFunc() returns two lists - this is a bug so we use uvSetCurrent[0] for now
                
                pm.menuItem(
                    checkBox=cBoxState,
                    command=lambda *args: pm.textureWindow(editor, setUvSet=item),
                    enableCommandRepeat=True,
                    label=uvSet,
                    parent=parentUI,
                )

    else: # No uv sets found
        pm.menuItem(
            enable=False, 
            enableCommandRepeat=False, 
            label="No object selected.",
            )