def __init__(self, parent, partClass, builderUI): MelForm.__init__(self, parent) self.partClass = partClass self.builderUI = builderUI self.UI_create = cmd.button( l=self.BUTTON_LBL_TEMPLATE % names.camelCaseToNice(partClass.GetPartName()), c=self.on_create, w=160) #now populate the ui for the part's args self.kwarg_UIs = {} #keyed by arg name kwargList = partClass.GetDefaultBuildKwargList() self.UI_argsLayout = MelForm(self) #everything has a parent attribute, so build it first prevUI = None for arg, default in kwargList: #skip UI for parent - assume selection always if arg == 'parent': continue setParent(self.UI_argsLayout) lbl = cmd.text(l=names.camelCaseToNice(arg, self.ABBRVS_TO_EXPAND)) #determine the function to use for building the UI for the arg buildMethodFromName = UI_FOR_NAMED_RIG_ARGS.get(arg, None) buildMethodFromType = getBuildUIMethodForObject( default) or MelTextField buildMethod = buildMethodFromName or buildMethodFromType self.kwarg_UIs[arg] = argUI = buildMethod(self.UI_argsLayout) argUI.setValue(default) #perform layout if prevUI is None: self.UI_argsLayout(e=True, af=((lbl, 'left', 15))) else: self.UI_argsLayout(e=True, ac=((lbl, 'left', 15, prevUI))) if isinstance(argUI, MelCheckBox): self.UI_argsLayout(e=True, af=((argUI, 'top', 3))) self.UI_argsLayout(e=True, af=((lbl, 'top', 3)), ac=((argUI, 'left', 5, lbl))) prevUI = argUI setParent(self) self(e=True, af=((self.UI_create, 'left', 0), (self.UI_argsLayout, 'right', 0)), ac=((self.UI_argsLayout, 'left', 0, self.UI_create)))
def __init__( self, parent, partClass, builderUI ): MelForm.__init__( self, parent ) self.partClass = partClass self.builderUI = builderUI self.UI_create = cmd.button( l=self.BUTTON_LBL_TEMPLATE % names.camelCaseToNice( partClass.GetPartName() ), c=self.on_create, w=160 ) #now populate the ui for the part's args self.kwarg_UIs = {} #keyed by arg name kwargList = partClass.GetDefaultBuildKwargList() self.UI_argsLayout = MelForm( self ) #everything has a parent attribute, so build it first prevUI = None for arg, default in kwargList: #skip UI for parent - assume selection always if arg == 'parent': continue setParent( self.UI_argsLayout ) lbl = cmd.text( l=names.camelCaseToNice( arg, self.ABBRVS_TO_EXPAND ) ) #determine the function to use for building the UI for the arg buildMethodFromName = UI_FOR_NAMED_RIG_ARGS.get( arg, None ) buildMethodFromType = getBuildUIMethodForObject( default ) or MelTextField buildMethod = buildMethodFromName or buildMethodFromType self.kwarg_UIs[ arg ] = argUI = buildMethod( self.UI_argsLayout ) argUI.setValue( default ) #perform layout if prevUI is None: self.UI_argsLayout( e=True, af=((lbl, 'left', 15)) ) else: self.UI_argsLayout( e=True, ac=((lbl, 'left', 15, prevUI)) ) if isinstance( argUI, MelCheckBox ): self.UI_argsLayout( e=True, af=((argUI, 'top', 3)) ) self.UI_argsLayout( e=True, af=((lbl, 'top', 3)), ac=((argUI, 'left', 5, lbl)) ) prevUI = argUI setParent( self ) self( e=True, af=((self.UI_create, 'left', 0), (self.UI_argsLayout, 'right', 0)), ac=((self.UI_argsLayout, 'left', 0, self.UI_create)) )
def GetPartName( cls ): ''' can be used to get a "nice" name for the part class ''' if cls.DISPLAY_NAME is None: return camelCaseToNice( cls.__name__ ) return cls.DISPLAY_NAME
def populate( self ): #remove any existing children self.clear() part = self.part assert isinstance( part, SkeletonPart ) #pimp out the UI lbl = MelButton( self, l=part.getPartName(), w=140, c=self.on_select ) #grab the args the rigging method takes argsForm = MelForm( self ) argsUIs = [] buildKwargs = part.getBuildKwargs() for arg in self.ARGS_TO_HIDE: buildKwargs.pop( arg, None ) for arg, argValue in buildKwargs.iteritems(): argLbl = MelLabel( argsForm, label=names.camelCaseToNice( arg ) ) #determine the function to use for building the UI for the arg buildMethodFromName = UI_FOR_NAMED_RIG_ARGS.get( arg, None ) buildMethodFromType = getBuildUIMethodForObject( argValue ) or MelTextField buildMethod = buildMethodFromName or buildMethodFromType #prioritize the method from name over the method from type argWidget = buildMethod( argsForm ) argWidget.setValue( argValue ) argsUIs.append( argLbl ) argsUIs.append( argWidget ) self.argUIs[ arg ] = argWidget try: inc = 1.0 / len( argsUIs ) except ZeroDivisionError: inc = 1.0 for n, ui in enumerate( argsUIs ): p = n*inc if n: argsForm( e=True, ac=((ui, 'left', 5, argsUIs[ n-1 ])) ) else: argsForm( e=True, af=((ui, 'left', 0)) ) #finally build the "rebuild" button reButt = MelButton( self, l="rebuild", c=self.on_rebuild, w=100 ) #perform layout... self.setWidth( 50 ) argsForm.setWidth( 50 ) self( e=True, af=((lbl, 'left', 0), (reButt, 'right', 0)), ac=((argsForm, 'left', 5, lbl), (argsForm, 'right', 0, reButt)) )
def populate(self): if not bool(self.rigTypes): self.setVisibility(False) return #remove any existing children self.clearArgs() part = self.part rigKwargs = part.getRigKwargs() #build the disable and optionbox for the rig method disableState = rigKwargs.get('disable', False) #grab the args the rigging method takes argsForm = self.UI_argsForm argsUIs = [] rigMethodName = rigKwargs.get('rigMethodName', self.rigTypes[0].__name__) rigClass = rigPrimitives.RigPart.GetNamedSubclass(rigMethodName) if rigClass is None: rigClass = part.RigTypes[0] zeroWeightTypes = MelCheckBox, MelOptionMenu argNamesAndDefaults = rigClass.GetDefaultBuildKwargList() for arg, default in argNamesAndDefaults: argValue = rigKwargs.get(arg, default) argLbl = MelLabel(argsForm, label=names.camelCaseToNice(arg)) #determine the function to use for building the UI for the arg buildMethodFromName = UI_FOR_NAMED_RIG_ARGS.get(arg, None) buildMethodFromType = getBuildUIMethodForObject( default) or MelTextField buildMethod = buildMethodFromName or buildMethodFromType argWidget = buildMethod(argsForm) argWidget.setValue(argValue, False) argWidget.setChangeCB(self.on_argCB) argLbl.enable(not disableState) argWidget.enable(not disableState) argsUIs.append(argLbl) argsUIs.append(argWidget) self.argUIs[arg] = argWidget #if there are no args - create an empty text widget otherwise maya will crash. yay! argsUIs.append(MelLabel(argsForm, label='')) argsForm.layout()
def populate( self ): if not bool( self.rigTypes ): self.setVisibility( False ) return #remove any existing children self.clearArgs() part = self.part rigKwargs = part.getRigKwargs() #build the disable and optionbox for the rig method disableState = rigKwargs.get( 'disable', False ) #grab the args the rigging method takes argsForm = self.UI_argsForm argsUIs = [] rigMethodName = rigKwargs.get( 'rigMethodName', self.rigTypes[ 0 ].__name__ ) rigClass = rigPrimitives.RigPart.GetNamedSubclass( rigMethodName ) if rigClass is None: rigClass = part.RigTypes[ 0 ] zeroWeightTypes = MelCheckBox, MelOptionMenu argNamesAndDefaults = rigClass.GetDefaultBuildKwargList() for arg, default in argNamesAndDefaults: argValue = rigKwargs.get( arg, default ) argLbl = MelLabel( argsForm, label=names.camelCaseToNice( arg ) ) #determine the function to use for building the UI for the arg buildMethodFromName = UI_FOR_NAMED_RIG_ARGS.get( arg, None ) buildMethodFromType = getBuildUIMethodForObject( default ) or MelTextField buildMethod = buildMethodFromName or buildMethodFromType argWidget = buildMethod( argsForm ) argWidget.setValue( argValue, False ) argWidget.setChangeCB( self.on_argCB ) argLbl.enable( not disableState ) argWidget.enable( not disableState ) argsUIs.append( argLbl ) argsUIs.append( argWidget ) self.argUIs[ arg ] = argWidget #if there are no args - create an empty text widget otherwise maya will crash. yay! argsUIs.append( MelLabel( argsForm, label='' ) ) argsForm.layout()
def addParent(self, parent, name=None): #sanity check - make sure the parent isn't either the control, the space, already in the list or a child of either the control or space if parent == self.getControl(): return elif parent == self.getSpace(): return if name is None: name = spaceSwitching.getSpaceName(self.getControl(), parent) if name is None: name = names.camelCaseToNice(str(parent)) self.UI_parents.append([parent, name])
def addParent( self, parent, name=None ): #sanity check - make sure the parent isn't either the control, the space, already in the list or a child of either the control or space if parent == self.getControl(): return elif parent == self.getSpace(): return if name is None: name = spaceSwitching.getSpaceName( self.getControl(), parent ) if name is None: name = names.camelCaseToNice( str( parent ) ) self.UI_parents.append( [parent, name] )
def __init__( self, parent, preset ): MelHSingleStretchLayout.__init__( self, parent ) self.preset = preset MelButton( self, l=names.camelCaseToNice( preset.name() ), c=self.on_load, w=160 ) spac = MelSpacer( self ) MelButton( self, l='Overwrite', c=self.on_overwrite, w=100 ) if preset.locale == presetsUI.LOCAL: self.UI_publish = MelButton( self, l='Publish', c=self.on_publish, w=100 ) #MelButton( self, l='Delete', c=self.on_remove, w=100 ) self.setStretchWidget( spac ) self.layout()
def setChain(self, dynamicChain): self.clear() self._chain = dynamicChain if dynamicChain is None: return dynChainNode = dynamicChain.getNode() MelLabel(self, l='Editing Dynamic Chain: %s' % dynChainNode) MelSeparator(self, h=15) attrs = listAttr(dynChainNode, k=True) or [] for attr in attrs: attrpath = '%s.%s' % (dynChainNode, attr) niceAttrName = camelCaseToNice(attr) #query the attribute type and build UI for the types we care about presenting to the user attrType = getAttr(attrpath, type=True) ui = None if attrType == 'bool': ui = MelCheckBox(self, l=niceAttrName) elif attrType == 'double': min, max = addAttr(attrpath, q=True, min=True), addAttr(attrpath, q=True, max=True) ui = LabelledFloatSlider(self, min, max, ll=niceAttrName, llw=65).getWidget() if ui is None: continue connectControl(ui, attrpath) MelSeparator(self, h=15) hLayout = MelHSingleStretchLayout(self) lbl = MelLabel(hLayout, l='Key Every N Frames') self.UI_nFrame = MelIntField(hLayout, v=4, min=1, max=10, step=1) self.UI_bake = MelButton(hLayout, l='Bake To Keys', c=self.on_bake) hLayout(e=True, af=((lbl, 'top', 0), (lbl, 'bottom', 0))) hLayout.padding = 10 hLayout.setStretchWidget(self.UI_bake) hLayout.layout()
def setChain( self, dynamicChain ): self.clear() self._chain = dynamicChain if dynamicChain is None: return dynChainNode = dynamicChain.getNode() MelLabel( self, l='Editing Dynamic Chain: %s' % dynChainNode ) MelSeparator( self, h=15 ) attrs = listAttr( dynChainNode, k=True ) or [] for attr in attrs: attrpath = '%s.%s' % (dynChainNode, attr) niceAttrName = camelCaseToNice( attr ) #query the attribute type and build UI for the types we care about presenting to the user attrType = getAttr( attrpath, type=True ) ui = None if attrType == 'bool': ui = MelCheckBox( self, l=niceAttrName ) elif attrType == 'double': min, max = addAttr( attrpath, q=True, min=True ), addAttr( attrpath, q=True, max=True ) ui = LabelledFloatSlider( self, min, max, ll=niceAttrName, llw=65 ).getWidget() if ui is None: continue connectControl( ui, attrpath ) MelSeparator( self, h=15 ) hLayout = MelHSingleStretchLayout( self ) lbl = MelLabel( hLayout, l='Key Every N Frames' ) self.UI_nFrame = MelIntField( hLayout, v=4, min=1, max=10, step=1 ) self.UI_bake = MelButton( hLayout, l='Bake To Keys', c=self.on_bake ) hLayout( e=True, af=((lbl, 'top', 0), (lbl, 'bottom', 0)) ) hLayout.padding = 10 hLayout.setStretchWidget( self.UI_bake ) hLayout.layout()
def generateNiceControlName( control ): niceName = getNiceName( control ) if niceName is not None: return niceName try: rigPart = RigPart.InitFromItem( control ) if rigPart is None: raise RigPartError( "null" ) controlName = rigPart.getControlName( control ) except RigPartError: controlName = str( control ) controlName = Name( controlName ) parity = controlName.get_parity() if parity == Parity.LEFT: controlName = 'Left '+ str( stripParity( controlName ) ) if parity == Parity.RIGHT: controlName = 'Right '+ str( stripParity( controlName ) ) else: controlName = str( controlName ) return camelCaseToNice( controlName )
def add(src, tgt, name=None, space=None, maintainOffset=True, nodeWithParentAttr=None, skipTranslationAxes=(), skipRotationAxes=(), constraintType=CONSTRAINT_PARENT): global AXES AXES = list(AXES) if space is None: space = listRelatives(src, p=True, pa=True)[0] if nodeWithParentAttr is None: nodeWithParentAttr = src if not name: name = getNiceName(tgt) if name is None: name = camelCaseToNice(str(tgt)) #if there is an existing constraint, check to see if the target already exists in its target list - if it does, return the condition used it uses attrState(space, ('t', 'r'), lock=False) existingConstraint = findConstraint(src) if existingConstraint: constraintType = nodeType(existingConstraint) constraintFunc = getattr(cmd, constraintType) targetsOnConstraint = constraintFunc(existingConstraint, q=True, tl=True) if tgt in targetsOnConstraint: idx = targetsOnConstraint.index(tgt) aliases = constraintFunc(existingConstraint, q=True, weightAliasList=True) cons = listConnections('%s.%s' % (existingConstraint, aliases[idx]), type='condition', d=False) return cons[0] #when skip axes are specified maya doesn't handle things properly - so make sure #ALL transform channels are connected, and remove unwanted channels at the end... preT, preR = getAttr('%s.t' % space)[0], getAttr('%s.r' % space)[0] if existingConstraint: chans = CONSTRAINT_CHANNELS[constraintType] for channel, constraintAttr in zip(*chans): for axis in AXES: spaceAttr = '%s.%s%s' % (space, channel, axis) conAttr = '%s.%s%s' % (existingConstraint, constraintAttr, axis) if not isConnected(conAttr, spaceAttr): connectAttr(conAttr, spaceAttr) #get the names for the parents from the parent enum attribute cmdOptionKw = {'mo': True} if maintainOffset else {} if objExists('%s.parent' % nodeWithParentAttr): srcs, names = getSpaceTargetsNames(src) addAttr('%s.parent' % nodeWithParentAttr, e=True, enumName=':'.join(names + [name])) #if we're building a pointConstraint instead of a parent constraint AND we already #have spaces on the object, we need to turn the -mo flag off regardless of what the #user set it to, as the pointConstraint maintain offset has different behaviour to #the parent constraint if constraintType in (CONSTRAINT_POINT, CONSTRAINT_ORIENT): cmdOptionKw = {} else: addAttr(nodeWithParentAttr, ln='parent', at="enum", en=name) setAttr('%s.parent' % nodeWithParentAttr, keyable=True) #now build the constraint constraintFunction = getattr(cmd, constraintType) constraint = constraintFunction(tgt, space, **cmdOptionKw)[0] weightAliasList = constraintFunction(constraint, q=True, weightAliasList=True) targetCount = len(weightAliasList) constraintAttr = weightAliasList[-1] condition = shadingNode('condition', asUtility=True, n='%s_to_space_%s#' % (getShortName(src), getShortName(tgt))) setAttr('%s.secondTerm' % condition, targetCount - 1) setAttr('%s.colorIfTrue' % condition, 1, 1, 1) setAttr('%s.colorIfFalse' % condition, 0, 0, 0) connectAttr('%s.parent' % nodeWithParentAttr, '%s.firstTerm' % condition) connectAttr('%s.outColorR' % condition, '%s.%s' % (constraint, constraintAttr)) #find out what symbol to use to find the parent attribute parentAttrIdx = 0 if not apiExtensions.cmpNodes(space, src): parentAttrIdx = triggered.addConnect(src, nodeWithParentAttr) #add the zooObjMenu commands to the object for easy space switching Trigger.CreateMenu(src, "parent to %s" % name, ChangeSpaceCmd.Create(targetCount - 1, parentAttrIdx)) #when skip axes are specified maya doesn't handle things properly - so make sure #ALL transform channels are connected, and remove unwanted channels at the end... for axis, value in zip(AXES, preT): if axis in skipTranslationAxes: attr = '%s.t%s' % (space, axis) delete(attr, icn=True) setAttr(attr, value) for axis, value in zip(AXES, preR): if axis in skipRotationAxes: attr = '%s.r%s' % (space, axis) delete(attr, icn=True) setAttr(attr, value) #make the space node non-keyable and lock visibility attrState(space, ['t', 'r', 's'], lock=True) attrState(space, 'v', *control.HIDE) return condition
def DISPLAY_NAME( cls ): return camelCaseToNice( cls.__name__ )
def GetPartName( cls ): ''' can be used to get a "nice" name for the part class ''' return camelCaseToNice( cls.__name__ )
def add( src, tgt, name=None, space=None, maintainOffset=True, nodeWithParentAttr=None, skipTranslationAxes=(), skipRotationAxes=(), constraintType=CONSTRAINT_PARENT ): global AXES AXES = list( AXES ) if space is None: space = listRelatives( src, p=True, pa=True )[ 0 ] if nodeWithParentAttr is None: nodeWithParentAttr = src if not name: name = getNiceName( tgt ) if name is None: name = camelCaseToNice( str( tgt ) ) #if there is an existing constraint, check to see if the target already exists in its target list - if it does, return the condition used it uses attrState( space, ('t', 'r'), lock=False ) existingConstraint = findConstraint( src ) if existingConstraint: constraintType = nodeType( existingConstraint ) constraintFunc = getattr( cmd, constraintType ) targetsOnConstraint = constraintFunc( existingConstraint, q=True, tl=True ) if tgt in targetsOnConstraint: idx = targetsOnConstraint.index( tgt ) aliases = constraintFunc( existingConstraint, q=True, weightAliasList=True ) cons = listConnections( '%s.%s' % (existingConstraint, aliases[ idx ]), type='condition', d=False ) return cons[ 0 ] #when skip axes are specified maya doesn't handle things properly - so make sure #ALL transform channels are connected, and remove unwanted channels at the end... preT, preR = getAttr( '%s.t' % space )[0], getAttr( '%s.r' % space )[0] if existingConstraint: chans = CONSTRAINT_CHANNELS[ constraintType ] for channel, constraintAttr in zip( *chans ): for axis in AXES: spaceAttr = '%s.%s%s' %( space, channel, axis) conAttr = '%s.%s%s' % (existingConstraint, constraintAttr, axis) if not isConnected( conAttr, spaceAttr ): connectAttr( conAttr, spaceAttr ) #get the names for the parents from the parent enum attribute cmdOptionKw = { 'mo': True } if maintainOffset else {} if objExists( '%s.parent' % nodeWithParentAttr ): srcs, names = getSpaceTargetsNames( src ) addAttr( '%s.parent' % nodeWithParentAttr, e=True, enumName=':'.join( names + [name] ) ) #if we're building a pointConstraint instead of a parent constraint AND we already #have spaces on the object, we need to turn the -mo flag off regardless of what the #user set it to, as the pointConstraint maintain offset has different behaviour to #the parent constraint if constraintType in ( CONSTRAINT_POINT, CONSTRAINT_ORIENT ): cmdOptionKw = {} else: addAttr( nodeWithParentAttr, ln='parent', at="enum", en=name ) setAttr( '%s.parent' % nodeWithParentAttr, keyable=True ) #now build the constraint constraintFunction = getattr( cmd, constraintType ) constraint = constraintFunction( tgt, space, **cmdOptionKw )[ 0 ] weightAliasList = constraintFunction( constraint, q=True, weightAliasList=True ) targetCount = len( weightAliasList ) constraintAttr = weightAliasList[ -1 ] condition = shadingNode( 'condition', asUtility=True, n='%s_to_space_%s#' % (getShortName( src ), getShortName( tgt )) ) setAttr( '%s.secondTerm' % condition, targetCount-1 ) setAttr( '%s.colorIfTrue' % condition, 1, 1, 1 ) setAttr( '%s.colorIfFalse' % condition, 0, 0, 0 ) connectAttr( '%s.parent' % nodeWithParentAttr, '%s.firstTerm' % condition ) connectAttr( '%s.outColorR' % condition, '%s.%s' % (constraint, constraintAttr) ) #find out what symbol to use to find the parent attribute parentAttrIdx = 0 if not apiExtensions.cmpNodes( space, src ): parentAttrIdx = triggered.addConnect( src, nodeWithParentAttr ) #add the zooObjMenu commands to the object for easy space switching Trigger.CreateMenu( src, "parent to %s" % name, ChangeSpaceCmd.Create( targetCount-1, parentAttrIdx ) ) #when skip axes are specified maya doesn't handle things properly - so make sure #ALL transform channels are connected, and remove unwanted channels at the end... for axis, value in zip( AXES, preT ): if axis in skipTranslationAxes: attr = '%s.t%s' % (space, axis) delete( attr, icn=True ) setAttr( attr, value ) for axis, value in zip( AXES, preR ): if axis in skipRotationAxes: attr = '%s.r%s' % (space, axis) delete( attr, icn=True ) setAttr( attr, value ) #make the space node non-keyable and lock visibility attrState( space, [ 't', 'r', 's' ], lock=True ) attrState( space, 'v', *control.HIDE ) return condition