Example #1
0
    def constraintWithWeightSyntax(*args, **kwargs):
        """
        Maya Bug Fix:
          - when queried, angle offsets would be returned in radians, not current angle unit

        Modifications:
          - added new syntax for querying the weight of a target object, by passing the constraint first::

                aimConstraint('pCube1_aimConstraint1', q=1, weight='pSphere1')
                aimConstraint('pCube1_aimConstraint1', q=1, weight=['pSphere1', 'pCylinder1'])
                aimConstraint('pCube1_aimConstraint1', q=1, weight=True)
        """
        if kwargs.get('query', kwargs.get('q', False) and len(args) == 1):
            # Fix the big with angle offset query always being in radians
            if kwargs.get('offset', kwargs.get('o', None)):
                return _general.getAttr(str(args[0]) + ".offset")

            # try seeing if we can apply the new weight query syntax
            targetObjects = kwargs.get('weight', kwargs.get('w', None))
            if targetObjects is not None:
                # old way caused KeyError if 'w' not in kwargs, even if 'weight' was!
                # targetObjects = kwargs.get( 'weight', kwargs['w'] )
                constraint = args[0]
                if 'constraint' in cmds.nodeType(constraint, inherited=1):
                    if targetObjects is True or (
                            # formerly, we allowed 'weight=[]' instead of
                            # 'weight=True' - while this is somewhat more
                            # confusing, continue to support it for backwards
                            # compatibility
                            _util.isIterable(targetObjects)
                            and not targetObjects):
                        targetObjects = func(constraint, q=1, targetList=1)
                    elif _util.isIterable(targetObjects):
                        # convert to list, in case it isn't one
                        targetObjects = list(targetObjects)
                    else:
                        targetObjects = [targetObjects]

                    constraintObj = cmds.listConnections(
                        constraint + '.constraintParentInverseMatrix',
                        s=1,
                        d=0)[0]
                    args = targetObjects + [constraintObj]
                    kwargs.pop('w', None)
                    kwargs['weight'] = True
        res = func(*args, **kwargs)
        if kwargs.get('query', kwargs.get('q', False) and len(args) == 1):
            if kwargs.get('weightAliasList', kwargs.get('wal', None)):
                res = [
                    _general.Attribute(args[0] + '.' + attr) for attr in res
                ]
            elif kwargs.get('worldUpObject', kwargs.get('wuo', None)):
                res = _factories.unwrapToPyNode(res)
            elif kwargs.get('targetList', kwargs.get('tl', None)):
                res = _factories.toPyNodeList(res)
        return res
Example #2
0
    def constraintWithWeightSyntax(*args, **kwargs):
        """
Maya Bug Fix:
  - when queried, angle offsets would be returned in radians, not current angle unit

Modifications:
  - added new syntax for querying the weight of a target object, by passing the constraint first::

        aimConstraint('pCube1_aimConstraint1', q=1, weight='pSphere1')
        aimConstraint('pCube1_aimConstraint1', q=1, weight=['pSphere1', 'pCylinder1'])
        aimConstraint('pCube1_aimConstraint1', q=1, weight=True)
        """
        if kwargs.get('query', kwargs.get('q', False) and len(args) == 1):
            # Fix the big with angle offset query always being in radians
            if kwargs.get('offset', kwargs.get('o', None)):
                return _general.getAttr(str(args[0]) + ".offset")

            # try seeing if we can apply the new weight query syntax
            targetObjects = kwargs.get('weight', kwargs.get('w', None))
            if targetObjects is not None:
                # old way caused KeyError if 'w' not in kwargs, even if 'weight' was!
                # targetObjects = kwargs.get( 'weight', kwargs['w'] )
                constraint = args[0]
                if 'constraint' in cmds.nodeType(constraint, inherited=1):
                    if targetObjects is True or (
                            # formerly, we allowed 'weight=[]' instead of
                            # 'weight=True' - while this is somewhat more
                            # confusing, continue to support it for backwards
                            # compatibility
                            _util.isIterable(targetObjects)
                            and not targetObjects):
                        targetObjects = func(constraint, q=1, targetList=1)
                    elif _util.isIterable(targetObjects):
                        # convert to list, in case it isn't one
                        targetObjects = list(targetObjects)
                    else:
                        targetObjects = [targetObjects]

                    constraintObj = cmds.listConnections(constraint + '.constraintParentInverseMatrix', s=1, d=0)[0]
                    args = targetObjects + [constraintObj]
                    kwargs.pop('w', None)
                    kwargs['weight'] = True
        res = func(*args, **kwargs)
        if kwargs.get('query', kwargs.get('q', False) and len(args) == 1):
            if kwargs.get('weightAliasList', kwargs.get('wal', None)):
                res = [_general.Attribute(args[0] + '.' + attr) for attr in res]
            elif kwargs.get('worldUpObject', kwargs.get('wuo', None)):
                res = _factories.unwrapToPyNode(res)
            elif kwargs.get('targetList', kwargs.get('tl', None)):
                res = _factories.toPyNodeList(res)
        return res
Example #3
0
        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName]['callbackId']
                if id is not None:
                    _api.MEventMessage.removeCallback( id )
                    if hasattr(id, 'disown'):
                        id.disown()
            except KeyError:
                _logger.warning("could not find callback id!")

            _pluginData[pluginName]['dependNodes'] = mayaTypes
            _logger.debug("adding new nodes: %s", ', '.join( mayaTypes ))

            for mayaType in mayaTypes:
                _logger.debug("Adding node: %s..." % mayaType)
                inheritance = _factories.getInheritance( mayaType )

                if not util.isIterable(inheritance):
                    _logger.warn( "could not get inheritance for mayaType %s" % mayaType)
                else:
                    #__logger.debug(mayaType, inheritance)
                    #__logger.debug("adding new node:", mayaType, apiEnum, inheritence)
                    # some nodes in the hierarchy for this node might not exist, so we cycle through all
                    parent = 'dependNode'

                    for node in inheritance:
                        nodeName = _factories.addPyNode( nodetypes, node, parent )
                        parent = node
                        if 'pymel.all' in sys.modules:
                            # getattr forces loading of Lazy object
                            setattr( sys.modules['pymel.all'], nodeName, getattr(nodetypes,nodeName) )
                _logger.debug("Done adding node %s" % mayaType)
    def wrappedCmd(*args, **kwargs):
        # we must get the cmd each time, because maya delays loading of functions until they are needed.
        # if we don't reload we'll keep the dummyFunc around
        new_cmd = getattr(maya.cmds, cmdname)
        #print args, kwargs
        # convert args to mel-friendly representation
        new_args = getMelRepresentation(args)

        # flatten list. this is necessary for list of components.  see Issue 71.  however, be sure that it's not an empty list/tuple
        if len(new_args) == 1 and util.isIterable(new_args[0]) and len(new_args[0]): #isinstance( new_args[0], (tuple, list) ):
            new_args = new_args[0]

        new_kwargs = getMelRepresentation(kwargs)
        #print new_args, new_kwargs
        try:
            res = new_cmd(*new_args, **new_kwargs)
        except objectErrorType, e:
            m = objectErrorReg.match(str(e))
            if m:
                import pymel.core.general
                obj = m.group(1)
                raise pymel.core.general._objectError(obj)

            else:
                # re-raise error
                raise
Example #5
0
def pythonToMel(arg):
    """
    convert a python object to a string representing an equivalent value in mel

    iterables are flattened.

    mapping types like dictionaries have their key value pairs flattened:
        { key1 : val1, key2 : val2 }  -- >  ( key1, val1, key2, val2 )

    """
    if util.isNumeric(arg):
        return str(arg)
    if isinstance(arg, datatypes.Vector):
        return '<<%f,%f,%f>>' % ( arg[0], arg[1], arg[2] )
    if util.isIterable(arg):
        if util.isMapping(arg):
            arg = list(_flatten(arg.iteritems()))
        else:
            arg = list(_flatten(arg))
        forceString = False
        for each in arg:
            if not util.isNumeric(each):
                forceString = True
                break

        if forceString:
            newargs = [ '"%s"' % x for x in arg ]
        else:
            newargs = [ str(x) for x in arg ]

        return '{%s}' % ','.join( newargs )

    # in order for PyNodes to get wrapped in quotes we have to treat special cases first,
    # we cannot simply test if arg is an instance of basestring because PyNodes are not
    return '"%s"' % cmds.encodeString(str(arg))
Example #6
0
def _flatten(iterables):
    for it in iterables:
        if util.isIterable(it):
            for element in it:
                yield element
        else:
            yield it
Example #7
0
    def wrappedCmd(*args, **kwargs):
        # we must get the cmd each time, because maya delays loading of functions until they are needed.
        # if we don't reload we'll keep the dummyFunc around
        new_cmd = getattr(maya.cmds, cmdname)
        #print args, kwargs
        # convert args to mel-friendly representation
        new_args = getMelRepresentation(args)

        # flatten list. this is necessary for list of components.  see Issue 71.  however, be sure that it's not an empty list/tuple
        if len(new_args) == 1 and util.isIterable(new_args[0]) and len(
                new_args[0]):  #isinstance( new_args[0], (tuple, list) ):
            new_args = new_args[0]

        new_kwargs = getMelRepresentation(kwargs)
        #print new_args, new_kwargs
        try:
            res = new_cmd(*new_args, **new_kwargs)
        except objectErrorType, e:
            m = objectErrorReg.match(str(e))
            if m:
                import pymel.core.general
                obj = m.group(1)
                raise pymel.core.general._objectError(obj)

            else:
                # re-raise error
                raise
Example #8
0
def _flatten(iterables):
    for it in iterables:
        if util.isIterable(it):
            for element in it:
                yield element
        else:
            yield it
Example #9
0
def _getInputFiles( input, recurse=False, exclude=(), melPathOnly=False, basePackage='' ):
    """
    Returns tuples of the form (packageName, melfile)
    """
    results = []
    if not util.isIterable( input ):
        input = [input]
    for f in input:
        results.extend(resolvePath(f, recurse=recurse, exclude=exclude, melPathOnly=melPathOnly, basePackage=basePackage))
    return results
Example #10
0
    def constraint(*args, **kwargs):
        """
Maya Bug Fix:
  - when queried, upVector, worldUpVector, and aimVector returned the name of the constraint instead of the desired values

Modifications:
  - added new syntax for querying the weight of a target object, by passing the constraint first::

        aimConstraint( 'pCube1_aimConstraint1', q=1, weight ='pSphere1' )
        aimConstraint( 'pCube1_aimConstraint1', q=1, weight =['pSphere1', 'pCylinder1'] )
        aimConstraint( 'pCube1_aimConstraint1', q=1, weight =[] )
        """
        if kwargs.get( 'query', kwargs.get('q', False) and len(args)==1) :

            # Fix the big with upVector, worldUpVector, and aimVector
            attrs = [
            'upVector', 'u',
            'worldUpVector', 'wu',
            'aimVector', 'a' ]

            for attr in attrs:
                if attr in kwargs:
                    return _general.datatypes.Vector( _general.getAttr(args[0] + "." + attr ) )

            # ...otherwise, try seeing if we can apply the new weight query syntax
            targetObjects =  kwargs.get( 'weight', kwargs.get('w', None) )
            if targetObjects is not None:
                # old way caused KeyError if 'w' not in kwargs, even if 'weight' was!
                # targetObjects = kwargs.get( 'weight', kwargs['w'] )
                constraint = args[0]
                if 'constraint' in cmds.nodeType( constraint, inherited=1 ):
                    if not _util.isIterable( targetObjects ):
                        targetObjects = [targetObjects]
                    elif not targetObjects:
                        targetObjects = func( constraint, q=1, targetList=1 )

                    constraintObj = cmds.listConnections( constraint + '.constraintParentInverseMatrix', s=1, d=0 )[0]
                    args = targetObjects + [constraintObj]
                    kwargs.pop('w',None)
                    kwargs['weight'] = True
        res = func(*args, **kwargs)
        if kwargs.get( 'query', kwargs.get('q', False) and len(args)==1) :
            if kwargs.get( 'weightAliasList', kwargs.get('wal', None) ):
                res = [_general.Attribute(args[0] + '.' + attr) for attr in res]
            elif kwargs.get( 'worldUpObject', kwargs.get('wuo', None) ):
                res = _factories.unwrapToPyNode(res)
            elif kwargs.get( 'targetList', kwargs.get('tl', None) ):
                res = _factories.toPyNodeList(res)
        return res
Example #11
0
        def addPluginPyNodes(*args):
            try:
                id = _pluginData[pluginName]['callbackId']
                if id is not None:
                    _api.MEventMessage.removeCallback( id )
                    if hasattr(id, 'disown'):
                        id.disown()
            except KeyError:
                _logger.warning("could not find callback id!")

            _pluginData[pluginName]['dependNodes'] = mayaTypes
            allTypes = set(cmds.ls(nodeTypes=1))
            for mayaType in mayaTypes:
                # make sure it's a 'valid' type - some plugins list node types
                # that don't show up in ls(nodeTypes=1), and aren't creatable
                # ...perhaps they're abstract types?
                # Unfortunately, can't check this, as only plugin I know of
                # that has such a node - mayalive, mlConstraint - is only
                # available up to 2009, which has a bug with allNodeTypes...
                # Oddly enough, mlConstraint WILL show up in allTypes here,
                # but not after the plugin is loaded / callback finishes...?
                if mayaType not in allTypes:
                    continue
                
                _logger.debug("Adding node: %s" % mayaType)
                try:
                    inheritance = _factories.getInheritance( mayaType )
                except Exception:
                    import traceback
                    _logger.debug(traceback.format_exc())
                    inheritance = None

                if inheritance == 'manip':
                    continue
                elif not inheritance or not util.isIterable(inheritance):
                    _logger.warn( "could not get inheritance for mayaType %s" % mayaType)
                else:
                    #__logger.debug(mayaType, inheritance)
                    #__logger.debug("adding new node:", mayaType, apiEnum, inheritence)
                    # some nodes in the hierarchy for this node might not exist, so we cycle through all
                    parent = 'dependNode'

                    for node in inheritance:
                        nodeName = _factories.addPyNode( nodetypes, node, parent )
                        parent = node
Example #12
0
def _getInputFiles(input,
                   recurse=False,
                   exclude=(),
                   melPathOnly=False,
                   basePackage=''):
    """
    Returns tuples of the form (packageName, melfile)
    """
    results = []
    if not util.isIterable(input):
        input = [input]
    for f in input:
        results.extend(
            resolvePath(f,
                        recurse=recurse,
                        exclude=exclude,
                        melPathOnly=melPathOnly,
                        basePackage=basePackage))
    return results
Example #13
0
def pythonToMel(arg):
    # type: (str) -> str
    """
    convert a python object to a string representing an equivalent value in mel

    iterables are flattened.

    mapping types like dictionaries have their key value pairs flattened:
        { key1 : val1, key2 : val2 }  -- >  ( key1, val1, key2, val2 )

    """
    if arg is None:
        return ''
    if arg is True or arg is False:
        return str(arg).lower()
    if util.isNumeric(arg):
        return str(arg)
    if isinstance(arg, datatypes.Vector):
        return '<<%f,%f,%f>>' % (arg[0], arg[1], arg[2])
    if util.isIterable(arg):
        if isinstance(arg, Mapping):
            arg = list(_flatten(arg.items()))
        else:
            arg = list(_flatten(arg))
        forceString = False
        for each in arg:
            if not util.isNumeric(each):
                forceString = True
                break

        if forceString:
            newargs = ['"%s"' % x for x in arg]
        else:
            newargs = [str(x) for x in arg]

        return '{%s}' % ','.join(newargs)

    # in order for PyNodes to get wrapped in quotes we have to treat special
    # cases first, we cannot simply test if arg is an instance of basestring
    # because PyNodes are not
    return '"%s"' % cmds.encodeString(str(arg))
Example #14
0
File: pmcmds.py Project: zewt/pymel
    def wrappedCmd(*args, **kwargs):
        # we must get the cmd each time, because maya delays loading of functions until they are needed.
        # if we don't reload we'll keep the dummyFunc around
        new_cmd = getattr(maya.cmds, cmdname)
        # print args, kwargs
        # convert args to mel-friendly representation
        new_args = getMelRepresentation(args)

        # flatten list. this is necessary for list of components.
        # see Issue 71.  however, be sure that it's not an empty list/tuple
        if len(new_args) == 1 and util.isIterable(new_args[0]) and len(new_args[0]):
            new_args = new_args[0]

        new_kwargs = getMelRepresentation(kwargs)
        # print new_args, new_kwargs
        try:
            res = new_cmd(*new_args, **new_kwargs)
        except objectErrorType as e:
            # % formatter deals with unicode, but keeps str if not unicode
            m = objectErrorReg.match('%s' % e)
            if m:
                import pymel.core.general
                obj = m.group(1)
                raise pymel.core.general._objectError(obj)

            else:
                # re-raise error
                raise

        # when editing, some of maya.cmds functions return empty strings and
        # some return idiotic statements like 'Values Edited'.
        # however, for UI's in particular, people use the edit command to get
        # a pymel class for existing objects.
        # return None when we get an empty string
        try:
            if res == '' and kwargs.get('edit', kwargs.get('e', False)):
                return None
        except AttributeError:
            pass
        return res
Example #15
0
def getMelRepresentation(args, recursionLimit=None, maintainDicts=True):
    """Will return a list which contains each element of the iterable 'args' converted to a mel-friendly representation.

    :Parameters:
        recursionLimit : int or None
            If an element of args is itself iterable, recursionLimit specifies the depth to which iterable elements
            will recursively search for objects to convert; if ``recursionLimit==0``, only the elements
            of args itself will be searched for PyNodes -  if it is 1, iterables within args will have getMelRepresentation called
            on them, etc.  If recursionLimit==None, then there is no limit to recursion depth.

        maintainDicts : bool
            In general, all iterables will be converted to tuples in the returned copy - however, if maintainDicts==True,
            then iterables for which ``util.isMapping()`` returns True will be returned as dicts.

    """
    if recursionLimit:
        recursionLimit -= 1

    if maintainDicts and util.isMapping(args):
        newargs = dict(args)
        argIterable = args.iteritems()
        isList = False
    else:
        newargs = list(args)
        argIterable = enumerate(args)
        isList = True

    for index, value in argIterable:
        try:
            newargs[index] = value.__melobject__()
        except AttributeError:
            if ((not recursionLimit)
                    or recursionLimit >= 0) and util.isIterable(value):
                # ...otherwise, recurse if not at recursion limit and  it's iterable
                newargs[index] = getMelRepresentation(value, recursionLimit,
                                                      maintainDicts)
    if isList:
        newargs = tuple(newargs)
    return newargs
def getMelRepresentation( args, recursionLimit=None, maintainDicts=True):
    """Will return a list which contains each element of the iterable 'args' converted to a mel-friendly representation.

    :Parameters:
        recursionLimit : int or None
            If an element of args is itself iterable, recursionLimit specifies the depth to which iterable elements
            will recursively search for objects to convert; if ``recursionLimit==0``, only the elements
            of args itself will be searched for PyNodes -  if it is 1, iterables within args will have getMelRepresentation called
            on them, etc.  If recursionLimit==None, then there is no limit to recursion depth.

        maintainDicts : bool
            In general, all iterables will be converted to tuples in the returned copy - however, if maintainDicts==True,
            then iterables for which ``util.isMapping()`` returns True will be returned as dicts.

    """
    if recursionLimit:
        recursionLimit -= 1


    if maintainDicts and util.isMapping(args):
        newargs = dict(args)
        argIterable = args.iteritems()
        isList = False
    else:
        newargs = list(args)
        argIterable = enumerate(args)
        isList = True

    for index, value in argIterable:
        try:
            newargs[index] = value.__melobject__()
        except AttributeError:
            if ( (not recursionLimit) or recursionLimit >= 0) and util.isIterable(value):
                # ...otherwise, recurse if not at recursion limit and  it's iterable
                newargs[index] = getMelRepresentation(value, recursionLimit, maintainDicts)
    if isList:
        newargs = tuple(newargs)
    return newargs
Example #17
0
def printTree( tree, depth=0 ):
    for branch in tree:
        if util.isIterable(branch):
            printTree( branch, depth+1)
        else:
            _logger.info('%s %s' % ('> '*depth,  branch))
Example #18
0
def getMelType(pyObj, exactOnly=True, allowBool=False, allowMatrix=False):
    """
    return the name of the closest MEL type equivalent for the given python
    object.

    MEL has no true boolean or matrix types, but it often reserves special
    treatment for them in other ways.

    To control the handling of these types, use `allowBool` and `allowMatrix`.
    For python iterables, the first element in the array is used to determine
    the type. for empty lists, 'string[]' is returned.

        >>> from pymel.all import *
        >>> getMelType( 1 )
        'int'
        >>> p = SCENE.persp
        >>> getMelType( p.translate.get() )
        'vector'
        >>> getMelType( datatypes.Matrix )
        'int[]'
        >>> getMelType( datatypes.Matrix, allowMatrix=True )
        'matrix'
        >>> getMelType( True )
        'int'
        >>> getMelType( True, allowBool=True)
        'bool'
        >>> # make a dummy class
        >>> class MyClass(object): pass
        >>> getMelType( MyClass ) # returns None
        >>> getMelType( MyClass, exactOnly=False )
        'MyClass'

    :Parameters:
        pyObj
            can be either a class or an instance.
        exactOnly : bool
            If True and no suitable MEL analog can be found, the function will
            return None.
            If False, types which do not have an exact mel analog will return
            the python type name as a string
        allowBool : bool
            if True and a bool type is passed, 'bool' will be returned.
            otherwise 'int'.
        allowMatrix : bool
            if True and a `Matrix` type is passed, 'matrix' will be returned.
            otherwise 'int[]'.

    :rtype: `str`


    """

    if inspect.isclass(pyObj):

        if issubclass(pyObj, basestring):
            return 'string'
        elif allowBool and issubclass(pyObj, bool):
            return 'bool'
        elif issubclass(pyObj, int):
            return 'int'
        elif issubclass(pyObj, float):
            return 'float'
        elif issubclass(pyObj, datatypes.VectorN):
            return 'vector'
        elif issubclass(pyObj, datatypes.MatrixN):
            if allowMatrix:
                return 'matrix'
            else:
                return 'int[]'

        elif not exactOnly:
            return pyObj.__name__

    else:
        if isinstance(pyObj, datatypes.VectorN):
            return 'vector'
        elif isinstance(pyObj, datatypes.MatrixN):
            if allowMatrix:
                return 'matrix'
            else:
                return 'int[]'
        elif util.isIterable(pyObj):
            try:
                return getMelType(pyObj[0], exactOnly=True) + '[]'
            except IndexError:
                # TODO : raise warning
                return 'string[]'
            except:
                return
        if isinstance(pyObj, basestring):
            return 'string'
        elif allowBool and isinstance(pyObj, bool):
            return 'bool'
        elif isinstance(pyObj, int):
            return 'int'
        elif isinstance(pyObj, float):
            return 'float'

        elif not exactOnly:
            return type(pyObj).__name__
def printTree( tree, depth=0 ):
    for branch in tree:
        if util.isIterable(branch):
            printTree( branch, depth+1)
        else:
            _logger.info('%s %s' % ('> '*depth,  branch))
Example #20
0
def valueControlGrp(name=None, create=False, dataType=None, slider=True, value=None, numberOfControls=1, **kwargs):
    """
    This function allows for a simplified interface for automatically creating UI's to control numeric values.

    A dictionary of keywords shared by all controls can be created and passed to this function and settings which don't pertain
    to the element being created will will be ignore.  For example, 'precision' will be ignored by all non-float UI and
    'sliderSteps' will be ignore by all non-slider UIs.

    :Parameters:
        dataType : string or class type
            The dataType that the UI should control.  It can be a type object or the string name of the type.
            For example for a boolean, you can specify 'bool' or pass in the bool class. Also, if the UI is meant to
            control an array, you can pass the type name as a stirng with a integer suffix representing the array length. ex. 'bool3'

        numberOfControls : int
            A parameter for specifying the number of controls per control group.  For example, for a checkBoxGrp, numberOfControls
            will map to the 'numberOfCheckBoxes' keyword.

        slider : bool
            Specify whether or not sliders should be used for int and float controls. Ignored for other
            types, as well as for int and float arrays

        value : int, int list, bool, bool list, float, float list, string, unicode, Path, Vector,
            The value for the control. If the value is for an array type, it should be a list or tuple of the appropriate
            number of elements.

    A straightforward example:

    .. python::

        settings = {}
        settings['step'] = 1
        settings['precision'] = 3
        settings['vertical'] = True # for all checkBoxGrps, lay out vertically
        win = window()
        columnLayout()
        setUITemplate( 'attributeEditorTemplate', pushTemplate=1 )
        boolCtr = valueControlGrp( dataType='bool', label='bool', **settings)
        bool3Ctr = valueControlGrp( dataType='bool', label='bool', numberOfControls=3, **settings)
        intCtr = valueControlGrp( dataType=int, label='int', slider=False, **settings)
        intSldr = valueControlGrp( dataType=int, label='int', slider=True, **settings)
        int3Ctrl= valueControlGrp( dataType=int, label='int', numberOfControls=3, **settings)
        floatCtr = valueControlGrp( dataType=float, label='float', slider=False, **settings)
        floatSldr = valueControlGrp( dataType=float, label='float', slider=True, **settings)
        pathCtrl = valueControlGrp( dataType=Path, label='path', **settings)
        win.show()


    Here's an example of how this is meant to be used in practice:

    .. python::

        settings = {}
        settings['step'] = 1
        settings['precision'] = 3
        win = window()
        columnLayout()
        types=[ ( 'donuts?',
                    bool,
                    True ),
                # bool arrays have a special label syntax that allow them to pass sub-labels
                ( [ 'flavors', ['jelly', 'sprinkles', 'glazed']],
                    'bool3',
                    [0,1,0]),
                ( 'quantity',
                  int,
                  12 ),
                ( 'delivery time',
                  float,
                  .69)
                ]
        for label, dt, val in types:
            valueControlGrp( dataType=dt, label=label, value=val, **settings)
        win.show()

    """

    def makeGetter(ctrl, methodName, num):
        def getter():
            res = []
            for i in range(num):
                res.append(getattr(ctrl, methodName + str(i + 1))())
            return res

        return getter

    def makeSetter(ctrl, methodName, num):
        def setter(args):
            for i in range(num):
                getattr(ctrl, methodName + str(i + 1))(args[i])

        return setter

    # the options below are only valid for certain control types.  they can always be passed to valueControlGrp, but
    # they will be ignore if not applicable to the control for this dataType.  this allows you to create a
    # preset configuration and pass it to the valueControlGrp for every dataType -- no need for creating switches, afterall
    # that's the point of this function

    sliderArgs = ["sliderSteps", "ss", "dragCommand", "dc"]
    fieldArgs = ["field", "f", "fieldStep", "fs", "fieldMinValue", "fmn", "fieldMaxValue", "fmx"]
    fieldSliderArgs = ["step", "s", "minValue", "min", "maxValue", "max", "extraLabel", "el"] + sliderArgs + fieldArgs
    floatFieldArgs = ["precision", "pre"]
    verticalArgs = ["vertical", "vr"]  # checkBoxGrp and radioButtonGrp only

    if _uitypes.PyUI._isBeingCreated(name, create, kwargs):
        assert dataType, "You must pass a dataType when creating a new control"
        if not isinstance(dataType, basestring):
            try:
                dataType = dataType.__name__
            except AttributeError:
                dataType = str(dataType)

        # if a dataType such as float3 or int2 was passed, get the number of ctrls
        try:
            buf = re.split("(\d+)", dataType)
            dataType = buf[0]
            numberOfControls = int(buf[1])
        except:
            pass
    else:
        # control command lets us get basic info even when we don't know the ui type
        dataType = control(name, q=1, docTag=1)
        assert dataType

    numberOfControls = int(numberOfControls)
    if numberOfControls < 1:
        numberOfControls = 1
    elif numberOfControls > 4:
        numberOfControls = 4

    # dataType = dataType.lower()
    kwargs.pop("dt", None)
    kwargs["docTag"] = dataType

    if dataType in ["bool"]:
        if numberOfControls > 1:
            kwargs.pop("ncb", None)
            kwargs["numberOfCheckBoxes"] = numberOfControls

        # remove field/slider and float kwargs
        for arg in fieldSliderArgs + floatFieldArgs:
            kwargs.pop(arg, None)

        # special label handling
        label = kwargs.get("label", kwargs.get("l", None))
        if label is not None:
            # allow label passing with additional sub-labels:
            #    ['mainLabel', ['subLabel1', 'subLabel2', 'subLabel3']]
            if _util.isIterable(label):
                label, labelArray = label
                kwargs.pop("l", None)
                kwargs["label"] = label
                kwargs["labelArray" + str(numberOfControls)] = labelArray

        ctrl = _uitypes.CheckBoxGrp(name, create, **kwargs)

        if numberOfControls > 1:
            getter = makeGetter(ctrl, "getValue", numberOfControls)
            setter = makeSetter(ctrl, "setValue", numberOfControls)
        else:
            getter = ctrl.getValue1
            setter = ctrl.setValue1
        # if hasDefault: ctrl.setValue1( int(default) )

    elif dataType in ["int"]:
        if numberOfControls > 1:
            kwargs.pop("nf", None)
            kwargs["numberOfFields"] = numberOfControls
            slider = False

        if slider:
            # remove float kwargs
            for arg in floatFieldArgs + verticalArgs:
                kwargs.pop(arg, None)
            # turn the field on by default
            if "field" not in kwargs and "f" not in kwargs:
                kwargs["field"] = True

            ctrl = _uitypes.IntSliderGrp(name, create, **kwargs)
            getter = ctrl.getValue
            setter = ctrl.setValue
        else:
            # remove field/slider and float kwargs
            for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
                kwargs.pop(arg, None)
            ctrl = _uitypes.IntFieldGrp(name, create, **kwargs)

            getter = ctrl.getValue1
            setter = ctrl.setValue1
        # if hasDefault: ctrl.setValue1( int(default) )

    elif dataType in ["float"]:
        if numberOfControls > 1:
            kwargs.pop("nf", None)
            kwargs["numberOfFields"] = numberOfControls
            slider = False

        if slider:
            for arg in verticalArgs:
                kwargs.pop(arg, None)

            # turn the field on by default
            if "field" not in kwargs and "f" not in kwargs:
                kwargs["field"] = True
            ctrl = _uitypes.FloatSliderGrp(name, create, **kwargs)
            getter = ctrl.getValue
            setter = ctrl.setValue
        else:
            # remove field/slider kwargs
            for arg in fieldSliderArgs + verticalArgs:
                kwargs.pop(arg, None)
            ctrl = _uitypes.FloatFieldGrp(name, create, **kwargs)
            getter = ctrl.getValue1
            setter = ctrl.setValue1
        # if hasDefault: ctrl.setValue1( float(default) )

    elif dataType in ["vector", "Vector"]:
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = VectorFieldGrp(name, create, **kwargs)
        getter = ctrl.getVector
        setter = ctrl.setValue1
        # if hasDefault: ctrl.setVector( default )

    elif dataType in ["path", "Path", "FileReference"]:  # or pathreg.search( argName.lower() ):
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = PathButtonGrp(name, create, **kwargs)
        getter = ctrl.getPath
        setter = ctrl.setPath
        # if hasDefault: ctrl.setText( default.__repr__() )

    elif dataType in ["string", "unicode", "str"]:
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = _uitypes.TextFieldGrp(name, create, **kwargs)
        getter = ctrl.getText
        setter = ctrl.setText
        # if hasDefault: ctrl.setText( str(default) )
    else:
        raise TypeError, "Unsupported dataType: %s" % dataType
    #        else:
    #            ctrl = _uitypes.TextFieldGrp( l=labelStr )
    #            getter = makeEvalGetter( ctrl.getText )
    #            #setter = ctrl.setValue1
    #            #if hasDefault: ctrl.setText( default.__repr__() )

    # new = ctrl( name, create, **kwargs )
    ctrl.getValue = getter
    ctrl.setValue = setter
    ctrl.dataType = ctrl.getDocTag

    if value is not None:
        ctrl.setValue(value)

    # TODO : remove setDocTag
    return ctrl
Example #21
0
def getMelType(pyObj, exactOnly=True, allowBool=False, allowMatrix=False):
    """
    return the name of the closest MEL type equivalent for the given python object.
    MEL has no true boolean or matrix types, but it often reserves special treatment for them in other ways.
    To control the handling of these types, use `allowBool` and `allowMatrix`.
    For python iterables, the first element in the array is used to determine the type. for empty lists, 'string[]' is
    returned.

        >>> from pymel.all import *
        >>> getMelType( 1 )
        'int'
        >>> p = SCENE.persp
        >>> getMelType( p.translate.get() )
        'vector'
        >>> getMelType( datatypes.Matrix )
        'int[]'
        >>> getMelType( datatypes.Matrix, allowMatrix=True )
        'matrix'
        >>> getMelType( True )
        'int'
        >>> getMelType( True, allowBool=True)
        'bool'
        >>> # make a dummy class
        >>> class MyClass(object): pass
        >>> getMelType( MyClass ) # returns None
        >>> getMelType( MyClass, exactOnly=False )
        'MyClass'

    :Parameters:
        pyObj
            can be either a class or an instance.
        exactOnly : bool
            If True and no suitable MEL analog can be found, the function will return None.
            If False, types which do not have an exact mel analog will return the python type name as a string
        allowBool : bool
            if True and a bool type is passed, 'bool' will be returned. otherwise 'int'.
        allowMatrix : bool
            if True and a `Matrix` type is passed, 'matrix' will be returned. otherwise 'int[]'.

    :rtype: `str`


    """

    if inspect.isclass(pyObj):

        if issubclass(pyObj, basestring): return 'string'
        elif allowBool and issubclass(pyObj, bool): return 'bool'
        elif issubclass(pyObj, int): return 'int'
        elif issubclass(pyObj, float): return 'float'
        elif issubclass(pyObj, datatypes.VectorN): return 'vector'
        elif issubclass(pyObj, datatypes.MatrixN):
            if allowMatrix:
                return 'matrix'
            else:
                return 'int[]'

        elif not exactOnly:
            return pyObj.__name__

    else:
        if isinstance(pyObj, datatypes.VectorN): return 'vector'
        elif isinstance(pyObj, datatypes.MatrixN):
            if allowMatrix:
                return 'matrix'
            else:
                return 'int[]'
        elif util.isIterable(pyObj):
            try:
                return getMelType(pyObj[0], exactOnly=True) + '[]'
            except IndexError:
                # TODO : raise warning
                return 'string[]'
            except:
                return
        if isinstance(pyObj, basestring): return 'string'
        elif allowBool and isinstance(pyObj, bool): return 'bool'
        elif isinstance(pyObj, int): return 'int'
        elif isinstance(pyObj, float): return 'float'

        elif not exactOnly:
            return type(pyObj).__name__
Example #22
0
def valueControlGrp(name=None,
                    create=False,
                    dataType=None,
                    slider=True,
                    value=None,
                    numberOfControls=1,
                    **kwargs):
    """
    This function allows for a simplified interface for automatically creating UI's to control numeric values.

    A dictionary of keywords shared by all controls can be created and passed to this function and settings which don't pertain
    to the element being created will will be ignore.  For example, 'precision' will be ignored by all non-float UI and
    'sliderSteps' will be ignore by all non-slider UIs.

    :Parameters:
        dataType : string or class type
            The dataType that the UI should control.  It can be a type object or the string name of the type.
            For example for a boolean, you can specify 'bool' or pass in the bool class. Also, if the UI is meant to
            control an array, you can pass the type name as a stirng with a integer suffix representing the array length. ex. 'bool3'

        numberOfControls : int
            A parameter for specifying the number of controls per control group.  For example, for a checkBoxGrp, numberOfControls
            will map to the 'numberOfCheckBoxes' keyword.

        slider : bool
            Specify whether or not sliders should be used for int and float controls. Ignored for other
            types, as well as for int and float arrays

        value : int, int list, bool, bool list, float, float list, string, unicode, Path, Vector,
            The value for the control. If the value is for an array type, it should be a list or tuple of the appropriate
            number of elements.

    A straightforward example::

        settings = {}
        settings['step'] = 1
        settings['precision'] = 3
        settings['vertical'] = True # for all checkBoxGrps, lay out vertically
        win = window()
        columnLayout()
        setUITemplate( 'attributeEditorTemplate', pushTemplate=1 )
        boolCtr = valueControlGrp( dataType='bool', label='bool', **settings)
        bool3Ctr = valueControlGrp( dataType='bool', label='bool', numberOfControls=3, **settings)
        intCtr = valueControlGrp( dataType=int, label='int', slider=False, **settings)
        intSldr = valueControlGrp( dataType=int, label='int', slider=True, **settings)
        int3Ctrl= valueControlGrp( dataType=int, label='int', numberOfControls=3, **settings)
        floatCtr = valueControlGrp( dataType=float, label='float', slider=False, **settings)
        floatSldr = valueControlGrp( dataType=float, label='float', slider=True, **settings)
        pathCtrl = valueControlGrp( dataType=Path, label='path', **settings)
        win.show()


    Here's an example of how this is meant to be used in practice::

        settings = {}
        settings['step'] = 1
        settings['precision'] = 3
        win = window()
        columnLayout()
        types=[ ( 'donuts?',
                    bool,
                    True ),
                # bool arrays have a special label syntax that allow them to pass sub-labels
                ( [ 'flavors', ['jelly', 'sprinkles', 'glazed']],
                    'bool3',
                    [0,1,0]),
                ( 'quantity',
                  int,
                  12 ),
                ( 'delivery time',
                  float,
                  .69)
                ]
        for label, dt, val in types:
            valueControlGrp( dataType=dt, label=label, value=val, **settings)
        win.show()

    """
    import uitypes

    def makeGetter(ctrl, methodName, num):
        def getter():
            res = []
            for i in range(num):
                res.append(getattr(ctrl, methodName + str(i + 1))())
            return res

        return getter

    def makeSetter(ctrl, methodName, num):
        def setter(args):
            for i in range(num):
                getattr(ctrl, methodName + str(i + 1))(args[i])

        return setter

    # the options below are only valid for certain control types.  they can always be passed to valueControlGrp, but
    # they will be ignore if not applicable to the control for this dataType.  this allows you to create a
    # preset configuration and pass it to the valueControlGrp for every dataType -- no need for creating switches, afterall
    # that's the point of this function

    sliderArgs = ['sliderSteps', 'ss', 'dragCommand', 'dc']
    fieldArgs = [
        'field', 'f', 'fieldStep', 'fs', 'fieldMinValue', 'fmn',
        'fieldMaxValue', 'fmx'
    ]
    fieldSliderArgs = [
        'step', 's', 'minValue', 'min', 'maxValue', 'max', 'extraLabel', 'el'
    ] + sliderArgs + fieldArgs
    floatFieldArgs = ['precision', 'pre']
    verticalArgs = ['vertical', 'vr']  # checkBoxGrp and radioButtonGrp only

    if uitypes.PyUI._isBeingCreated(name, create, kwargs):
        assert dataType, "You must pass a dataType when creating a new control"
        if not isinstance(dataType, basestring):
            try:
                dataType = dataType.__name__
            except AttributeError:
                dataType = str(dataType)

        # if a dataType such as float3 or int2 was passed, get the number of ctrls
        try:
            buf = re.split('(\d+)', dataType)
            dataType = buf[0]
            numberOfControls = int(buf[1])
        except:
            pass
    else:
        # control command lets us get basic info even when we don't know the ui type
        dataType = control(name, q=1, docTag=1)
        assert dataType

    numberOfControls = int(numberOfControls)
    if numberOfControls < 1:
        numberOfControls = 1
    elif numberOfControls > 4:
        numberOfControls = 4

    #dataType = dataType.lower()
    kwargs.pop('dt', None)
    kwargs['docTag'] = dataType

    if dataType in ["bool"]:
        if numberOfControls > 1:
            kwargs.pop('ncb', None)
            kwargs['numberOfCheckBoxes'] = numberOfControls

        # remove field/slider and float kwargs
        for arg in fieldSliderArgs + floatFieldArgs:
            kwargs.pop(arg, None)

        # special label handling
        label = kwargs.get('label', kwargs.get('l', None))
        if label is not None:
            # allow label passing with additional sub-labels:
            #    ['mainLabel', ['subLabel1', 'subLabel2', 'subLabel3']]
            if _util.isIterable(label):
                label, labelArray = label
                kwargs.pop('l', None)
                kwargs['label'] = label
                kwargs['labelArray' + str(numberOfControls)] = labelArray

        ctrl = uitypes.CheckBoxGrp(name, create, **kwargs)

        if numberOfControls > 1:
            getter = makeGetter(ctrl, 'getValue', numberOfControls)
            setter = makeSetter(ctrl, 'setValue', numberOfControls)
        else:
            getter = ctrl.getValue1
            setter = ctrl.setValue1
        #if hasDefault: ctrl.setValue1( int(default) )

    elif dataType in ["int"]:
        if numberOfControls > 1:
            kwargs.pop('nf', None)
            kwargs['numberOfFields'] = numberOfControls
            slider = False

        if slider:
            # remove float kwargs
            for arg in floatFieldArgs + verticalArgs:
                kwargs.pop(arg, None)
            # turn the field on by default
            if 'field' not in kwargs and 'f' not in kwargs:
                kwargs['field'] = True

            ctrl = uitypes.IntSliderGrp(name, create, **kwargs)
            getter = ctrl.getValue
            setter = ctrl.setValue
        else:
            # remove field/slider and float kwargs
            for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
                kwargs.pop(arg, None)
            ctrl = uitypes.IntFieldGrp(name, create, **kwargs)

            getter = ctrl.getValue1
            setter = ctrl.setValue1
        #if hasDefault: ctrl.setValue1( int(default) )

    elif dataType in ["float"]:
        if numberOfControls > 1:
            kwargs.pop('nf', None)
            kwargs['numberOfFields'] = numberOfControls
            slider = False

        if slider:
            for arg in verticalArgs:
                kwargs.pop(arg, None)

            # turn the field on by default
            if 'field' not in kwargs and 'f' not in kwargs:
                kwargs['field'] = True
            ctrl = uitypes.FloatSliderGrp(name, create, **kwargs)
            getter = ctrl.getValue
            setter = ctrl.setValue
        else:
            # remove field/slider kwargs
            for arg in fieldSliderArgs + verticalArgs:
                kwargs.pop(arg, None)
            ctrl = uitypes.FloatFieldGrp(name, create, **kwargs)
            getter = ctrl.getValue1
            setter = ctrl.setValue1
        #if hasDefault: ctrl.setValue1( float(default) )

    elif dataType in ["vector", "Vector"]:
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = VectorFieldGrp(name, create, **kwargs)
        getter = ctrl.getVector
        setter = ctrl.setValue1
        #if hasDefault: ctrl.setVector( default )

    elif dataType in ["path", "Path", "FileReference"
                      ]:  # or pathreg.search( argName.lower() ):
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = PathButtonGrp(name, create, **kwargs)
        getter = ctrl.getPath
        setter = ctrl.setPath
        #if hasDefault: ctrl.setText( default.__repr__() )

    elif dataType in ["string", "unicode", "str"]:
        # remove field/slider kwargs
        for arg in fieldSliderArgs + floatFieldArgs + verticalArgs:
            kwargs.pop(arg, None)
        ctrl = uitypes.TextFieldGrp(name, create, **kwargs)
        getter = ctrl.getText
        setter = ctrl.setText
        #if hasDefault: ctrl.setText( str(default) )
    else:
        raise TypeError, "Unsupported dataType: %s" % dataType


#        else:
#            ctrl = uitypes.TextFieldGrp( l=labelStr )
#            getter = makeEvalGetter( ctrl.getText )
#            #setter = ctrl.setValue1
#            #if hasDefault: ctrl.setText( default.__repr__() )

#new = ctrl( name, create, **kwargs )
    ctrl.getValue = getter
    ctrl.setValue = setter
    ctrl.dataType = ctrl.getDocTag

    if value is not None:
        ctrl.setValue(value)

    # TODO : remove setDocTag
    return ctrl