def __init__(self, allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion() < Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int', 'item'), ('int', 'state')], returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string', 'item'), ('string', 'newName')]) self.control = cmds.treeView( numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand, dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control, e=True, enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False
def __init__(self, annotation, name, value=None): self.annotation = annotation self.name = name self.intensityTexts = {0.0: "low", 0.33: "medium", 0.7: "high"} self.changeCommand = Signal() self.__value = Options.loadOption(name, 1.0 if value is None else value)
def __init__(self): self.items = [] # type: list[InfluencesListEntry] self.mirrorMode = False self.mapper = None # type: InfluenceMapping self.currentInfluencesSelection = [] self.onDelete = Signal("influence mapping preview: onDelete")
def __init__(self): ''' :param str licensePath: :param Server licenseServerInterface: ''' self.licensePath = None self.status = None self.changed = Signal("licenseStatus")
def __init__(self, range=(0.0, 1.0)): assert (len(range) == 2) self.model = None self.floatField = None self.slider = None self.onChange = Signal("floatSliderChange") self.onChanging = Signal("floatSliderChanging") self.range = range self.flexibleRange = False
def __init__(self, range=[0.0, 1.0]): assert len(range) == 2 self.model = None self.floatField = None self.slider = None self.onChange = Signal() self.onChanging = Signal() self.range = range self.flexibleRange = False
class ObservedValue(object): def __init__(self, name, initialValue=None): self.changed = Signal(name="cachedValue change (%s)" % name) self.value = initialValue def get(self): return self.value def set(self, value): self.value = value self.changed.emit()
class Status: ''' given licensePath, track license status. works both with ngstKey licenses and RLM licenses ''' def __init__(self): ''' :param str licensePath: :param Server licenseServerInterface: ''' self.licensePath = None self.status = None self.changed = Signal("licenseStatus") def setLicensePath(self, licensePath): self.licensePath = licensePath self.recalculate() def setStatus(self, status): log.info("changing license status to %s", status) self.status = status self.changed.emit() def recalculate(self): if self.licensePath is None: self.licensePath = getLicensePath() ngstKeyLicenses = fileFormat.discoverLicenseFiles(self.licensePath) if len(ngstKeyLicenses) == 0: # no ngstkey licenses found, checking RLM self.setStatus( cmds.ngSkinToolsLicense(validateLicense=True, licensePath=self.licensePath)) else: for license in ngstKeyLicenses: status = cmds.ngSkinToolsLicense( validateLicense=True, hostid=license.get('hostid'), licenseKey=license.get('licensekey'), licenseType=license.get('licenseType'), signature=license.get('sig')) if status == 0: self.setStatus(status) break return self.status def isLicenseActive(self): return self.status == 0 def getDefaultLicenseFileName(self): return os.path.join(self.licensePath, "ngskintools.lic")
class IntensitySlider: def __init__(self, annotation, name, value=None): self.annotation = annotation self.name = name self.intensityTexts = {0.0: "low", 0.33: "medium", 0.7: "high"} self.changeCommand = Signal() self.__value = Options.loadOption(name, 1.0 if value is None else value) def create(self): form = FormLayout(width=100) self.intensityIndicator = cmds.textField( width=Constants.NUMBER_FIELD_WIDTH, editable=False, annotation=self.annotation) self.sliderIntensity = cmds.floatSlider(min=0, max=1, step=0.05, value=self.__value, cc=self.sliderChange, annotation=self.annotation) form.attachForm(self.intensityIndicator, 0, None, 0, 0) form.attachForm(self.sliderIntensity, 2, 0, None, None) form.attachControl(self.sliderIntensity, self.intensityIndicator, None, None, None, 0) self.updateIntensityDisplay() return form def getIntensity(self): return cmds.floatSlider(self.sliderIntensity, q=True, value=True) def sliderChange(self, *args): self.updateIntensityDisplay() Options.saveOption(self.name, self.getIntensity()) self.changeCommand.emit() def updateIntensityDisplay(self): currIntensity = self.getIntensity() displayText = None displayedValue = -1 for currValue, currText in self.intensityTexts.items(): if currValue <= currIntensity and currValue > displayedValue: displayText = currText displayedValue = currValue cmds.textField(self.intensityIndicator, e=True, text=displayText)
def __init__(self, newLayerMode): BaseDialog.__init__(self) self.title = "New Layer" if newLayerMode else "Layer Properties" self.buttons = [self.BUTTON_OK, self.BUTTON_CANCEL] self.layerNameValue = ValueModel() self.layerOpacityValue = ValueModel() self.newLayerMode = newLayerMode self.onOpacityChange = Signal("Layer Opacity changed")
class IntensitySlider: def __init__(self,annotation,name,value=None): self.annotation = annotation self.name = name self.intensityTexts = {0.0:"low",0.33:"medium",0.7:"high"} self.changeCommand = Signal() self.__value = Options.loadOption(name, 1.0 if value is None else value); def create(self): form = FormLayout(width=100) self.intensityIndicator = cmds.textField(width=Constants.NUMBER_FIELD_WIDTH,editable=False,annotation=self.annotation); self.sliderIntensity = cmds.floatSlider(min=0, max=1, step=0.05, value=self.__value,cc=self.sliderChange,annotation=self.annotation ) form.attachForm(self.intensityIndicator,0,None,0,0) form.attachForm(self.sliderIntensity,2,0,None,None) form.attachControl(self.sliderIntensity,self.intensityIndicator,None,None,None,0) self.updateIntensityDisplay() return form def getIntensity(self): return cmds.floatSlider(self.sliderIntensity,q=True,value=True) def sliderChange(self,*args): self.updateIntensityDisplay() Options.saveOption(self.name, self.getIntensity()) self.changeCommand.emit() def updateIntensityDisplay(self): currIntensity = self.getIntensity() displayText = None displayedValue = -1 for currValue,currText in self.intensityTexts.items(): if currValue<=currIntensity and currValue>displayedValue: displayText = currText displayedValue = currValue cmds.textField(self.intensityIndicator,e=True,text=displayText);
def __init__(self, allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand self.control = cmds.treeView( numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand, dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control, e=True, enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal("onSelectionChanged") self.__selectionChanging = False self.__itemNameChanging = False
class ValueUIWrapper(BaseUIWrapper): ''' UI wrapper for controls that have a settable/gettable value (like float field) ''' def __init__(self, uiCommand=None, annotation=''): BaseUIWrapper.__init__(self, uiCommand, annotation) self.valueKeyName = 'value' self.changeCommand = Signal("ValueUIWrapper changeCommand") def getValue(self): return self.uiCommand(self.field, q=True, **{self.valueKeyName: True}) def setValue(self, value): args = {self.valueKeyName: value} self.uiCommand(self.field, e=True, **args) def createUI(self, **kargs): kargs['changeCommand'] = self.fieldChanged BaseUIWrapper.createUI(self, **kargs) def fieldChanged(self, *args): self.changeCommand.emit()
class ValueUIWrapper(BaseUIWrapper): ''' UI wrapper for controls that have a settable/gettable value (like float field) ''' def __init__(self,uiCommand=None,annotation=''): BaseUIWrapper.__init__(self,uiCommand,annotation) self.valueKeyName = 'value' self.changeCommand = Signal() def getValue(self): return self.uiCommand(self.field,q=True,**{self.valueKeyName:True}) def setValue(self,value): args = {self.valueKeyName:value} self.uiCommand(self.field,e=True,**args) def createUI(self,**kargs): kargs['changeCommand'] = self.fieldChanged BaseUIWrapper.createUI(self,**kargs) def fieldChanged(self,*args): self.changeCommand.emit()
def __init__(self,allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion()<Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int','item'),('int','state')],returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string','item'),('string','newName')]) self.control = cmds.treeView(numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand,dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control,e=True,enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False
def __init__(self, name, initialValue=None): self.changed = Signal(name="cachedValue change (%s)" % name) self.value = initialValue
class TreeViewIDList: def __init__(self, allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion() < Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int', 'item'), ('int', 'state')], returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string', 'item'), ('string', 'newName')]) self.control = cmds.treeView(numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand) if Utils.getMayaVersion() >= Utils.MAYA2011: cmds.treeView(self.control, e=True, enableKeys=True) self.selectedID = None self.selectedItems = set() self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False def setItems(self, newItems, selectedID=None): if selectedID is None: selectedID = self.getSelectedID() if self.items != newItems: self.doSetItems(newItems) self.items = newItems self.selectByID(selectedID) def selectionChanged(self, item, selected): self.__selectionChanging = True try: selected = int(selected) item = int(item) if selected: self.selectedItems.add(item) self.selectedID = item self.onSelectionChanged.emit() else: self.selectedItems.discard(item) finally: self.__selectionChanging = False return True def internalEditLabelCommand(self, item, newName): ''' indirectly executed by treeview inplace editor; return non empty string to let treeView know that rename succeeded ''' return '' def editLabelCommand(self, item, newName): ''' subclasses should override internalEditLabelCommand instead ''' self.__itemNameChanging = True try: return self.internalEditLabelCommand(item, newName) finally: self.__itemNameChanging = False def doSetItems(self, newItems): if self.__selectionChanging: raise Exception("cannot change items while selection is changing") if self.__itemNameChanging: # raise Exception("cannot change items while item name is changing") # silently exit: should be no harm ignoring new items as the only thing that changed # is label name, and we already reflect that in UI return self.selectedID = None self.selectedItems.clear() #cmds.treeView(self.control,e=True,clearSelection=True) cmds.treeView(self.control, e=True, removeAll=True) for i in newItems: cmds.treeView(self.control, e=True, addItem=(i.id, '')) cmds.treeView(self.control, e=True, displayLabel=(i.id, i.displayName), displayLabelSuffix=(i.id, i.suffix)) def getSelectedID(self): return self.selectedID def getSelectedNames(self): return [i.name for i in self.items if (i.id in self.selectedItems)] def getSelectedIDs(self): return list(self.selectedItems) def selectByID(self, id): if self.__selectionChanging: return if self.selectedID == id: return self.selectedItems.add(id) for i in self.items: cmds.treeView(self.control, e=True, si=(i.id, int(i.id == id)))
def __init__(self,annotation,name,value=None): self.annotation = annotation self.name = name self.intensityTexts = {0.0:"low",0.33:"medium",0.7:"high"} self.changeCommand = Signal() self.__value = Options.loadOption(name, 1.0 if value is None else value);
class TreeViewIDList(object): def __init__(self,allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion()<Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int','item'),('int','state')],returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string','item'),('string','newName')]) self.control = cmds.treeView(numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand,dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control,e=True,enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False def handleDragDropCommand(self,itemList,prevParents,prevIndexes,newParent,newIndexes,itemBefore,itemAfter): pass def setItems(self,newItems,selectedID): ''' sets new items in the ID list; :param list newItems: list of IdToNameEntry :param selectedID: item to select in the list after setting the items ''' log.debug("set items: {0},selected id: {1}".format(newItems,selectedID)) if self.items!=newItems: if self.__selectionChanging: raise Exception("cannot change items while selection is changing") if self.__itemNameChanging: # raise Exception("cannot change items while item name is changing") # silently exit: should be no harm ignoring new items as the only thing that changed # is label name, and we already reflect that in UI return self.selectedItems = [] cmds.treeView(self.control,e=True,clearSelection=True) cmds.treeView(self.control,e=True,removeAll=True) for i in newItems: cmds.treeView(self.control,e=True,addItem=(i.id,'')) cmds.treeView(self.control,e=True,displayLabel=(i.id,i.displayName),displayLabelSuffix=(i.id,i.suffix)) self.items = newItems self.selectByID(selectedID) def getIdByInternalId(self,internalId): ''' given item ID (internal UI label), return actual item ID from the item. ''' if internalId is None: return None for i in self.items: if i.internalId==internalId: return i.id raise Exception("invalid internal ID: {!r}".format(internalId)) def selectionChanged(self,internalId,selected): ''' UI event handler for when selection is changed there are events fired for items being unselected (``selected`` is 0) and for items being selected (``selected`` is 1) ''' item = self.getIdByInternalId(internalId) self.__selectionChanging = True try: if selected: if item is not None and item not in self.selectedItems: self.selectedItems.append(item) self.onSelectionChanged.emit() else: if item in self.selectedItems: self.selectedItems.remove(item) self.onSelectionChanged.emit() finally: self.__selectionChanging = False return True def internalEditLabelCommand(self,item,newName): ''' indirectly executed by treeview inplace editor; return non empty string to let treeView know that rename succeeded :return: True, if rename was successful; false otherwise. ''' return False def editLabelCommand(self,internalId,newName): ''' UI event handler for when user edits item label; subclasses should override internalEditLabelCommand instead ''' self.__itemNameChanging = True try: item = self.getIdByInternalId(internalId) renameSuccessful = self.internalEditLabelCommand(item, newName) if not renameSuccessful: return '' return internalId finally: self.__itemNameChanging = False def getSelectedNames(self): ''' :return: names of all currently selected items ''' return [i.name for i in self.items if (i.id in self.selectedItems)] def getSelectedID(self): ''' :return: ID of currently selected item ''' return None if not self.selectedItems else self.selectedItems[-1] def getSelectedIDs(self): ''' :return: IDs of selected items ''' return self.selectedItems def selectByID(self,itemId): self.setSelectedIDs([itemId]) def setSelectedIDs(self,ids): log.debug("selecting by ID: {0}".format(id)) if self.__selectionChanging: return # remove any null items ids = [i for i in ids if i is not None] if self.selectedItems == ids: return self.selectedItems = ids for i in self.items: cmds.treeView(self.control,e=True,si=(i.internalId,int(i.id in ids)))
class TreeViewIDList(object): def __init__(self, allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion() < Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int', 'item'), ('int', 'state')], returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string', 'item'), ('string', 'newName')]) self.control = cmds.treeView( numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand, dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control, e=True, enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False def handleDragDropCommand(self, itemList, prevParents, prevIndexes, newParent, newIndexes, itemBefore, itemAfter): pass def setItems(self, newItems, selectedID): ''' sets new items in the ID list; :param list newItems: list of IdToNameEntry :param selectedID: item to select in the list after setting the items ''' log.debug("set items: {0},selected id: {1}".format( newItems, selectedID)) if self.items != newItems: if self.__selectionChanging: raise Exception( "cannot change items while selection is changing") if self.__itemNameChanging: # raise Exception("cannot change items while item name is changing") # silently exit: should be no harm ignoring new items as the only thing that changed # is label name, and we already reflect that in UI return self.selectedItems = [] cmds.treeView(self.control, e=True, clearSelection=True) cmds.treeView(self.control, e=True, removeAll=True) for i in newItems: cmds.treeView(self.control, e=True, addItem=(i.id, '')) cmds.treeView(self.control, e=True, displayLabel=(i.id, i.displayName), displayLabelSuffix=(i.id, i.suffix)) self.items = newItems self.selectByID(selectedID) def getIdByInternalId(self, internalId): ''' given item ID (internal UI label), return actual item ID from the item. ''' if internalId is None: return None for i in self.items: if i.internalId == internalId: return i.id raise Exception("invalid internal ID: {!r}".format(internalId)) def selectionChanged(self, internalId, selected): ''' UI event handler for when selection is changed there are events fired for items being unselected (``selected`` is 0) and for items being selected (``selected`` is 1) ''' item = self.getIdByInternalId(internalId) self.__selectionChanging = True try: if selected: if item is not None and item not in self.selectedItems: self.selectedItems.append(item) self.onSelectionChanged.emit() else: if item in self.selectedItems: self.selectedItems.remove(item) self.onSelectionChanged.emit() finally: self.__selectionChanging = False return True def internalEditLabelCommand(self, item, newName): ''' indirectly executed by treeview inplace editor; return non empty string to let treeView know that rename succeeded :return: True, if rename was successful; false otherwise. ''' return False def editLabelCommand(self, internalId, newName): ''' UI event handler for when user edits item label; subclasses should override internalEditLabelCommand instead ''' self.__itemNameChanging = True try: item = self.getIdByInternalId(internalId) renameSuccessful = self.internalEditLabelCommand(item, newName) if not renameSuccessful: return '' return internalId finally: self.__itemNameChanging = False def getSelectedNames(self): ''' :return: names of all currently selected items ''' return [i.name for i in self.items if (i.id in self.selectedItems)] def getSelectedID(self): ''' :return: ID of currently selected item ''' return None if not self.selectedItems else self.selectedItems[-1] def getSelectedIDs(self): ''' :return: IDs of selected items ''' return self.selectedItems def selectByID(self, itemId): self.setSelectedIDs([itemId]) def setSelectedIDs(self, ids): log.debug("selecting by ID: {0}".format(id)) if self.__selectionChanging: return # remove any null items ids = [i for i in ids if i is not None] if self.selectedItems == ids: return self.selectedItems = ids for i in self.items: cmds.treeView(self.control, e=True, si=(i.internalId, int(i.id in ids)))
def __init__(self, parent): self.parent = parent self.mainLayout = None self.filterChanged = Signal("Influence filter changed") self.isVisible = PersistentValueModel( Options.VAR_OPTION_PREFIX + "_InfluenceFilterVisible", False)
class InfluenceFilterUi: VAR_PREFIX = 'ngSkinToolsInfluenceFilter_' def __init__(self, parent): self.parent = parent self.mainLayout = None self.filterChanged = Signal("Influence filter changed") self.isVisible = PersistentValueModel( Options.VAR_OPTION_PREFIX + "_InfluenceFilterVisible", False) def createUI(self, parent): result = group = self.mainLayout = uiWrappers.frameLayout( parent=parent, label="Influence Filter", marginWidth=Constants.MARGIN_SPACING_HORIZONTAL, marginHeight=Constants.MARGIN_SPACING_VERTICAL, collapsable=True, expandCommand=self.isVisible.save, collapseCommand=self.isVisible.save, borderStyle='etchedIn') cmds.frameLayout(group, e=True, collapse=self.isVisible.get()) column = cmds.columnLayout( parent=group, adjustableColumn=1, rowSpacing=Constants.MARGIN_SPACING_VERTICAL) form = FormLayout(parent=column) label = cmds.text(label='Influence Filter:') textField = self.influenceNameFilter = TextEdit( annotation="Filter influence list by name") clearButton = cmds.button(label='clear', width=50, command=self.clearNameFilter) form.attachForm(label, 10, None, 0, Constants.MARGIN_SPACING_HORIZONTAL) form.attachForm(clearButton, 10, Constants.MARGIN_SPACING_HORIZONTAL, 0, None) form.attachForm(textField, 10, None, 0, None) form.attachControl(textField, label, None, None, None, Constants.MARGIN_SPACING_HORIZONTAL) form.attachControl(textField, clearButton, None, Constants.MARGIN_SPACING_HORIZONTAL, None, None) textField.changeCommand.addHandler(self.filterChanged.emit) cmds.setParent(result) cmds.radioCollection() form = FormLayout(parent=column) self.radioAllInfluences = RadioButtonField(self.VAR_PREFIX + "allInfluences", defaultValue=1, label='Show all influences') self.radioAllInfluences.changeCommand.addHandler( self.radioAllInfluencesChanged) self.radioActiveInfluences = RadioButtonField( self.VAR_PREFIX + "activeInfluences", defaultValue=0, label='Only influences with non-zero weights') form.attachForm(self.radioAllInfluences, 0, 0, None, 90) form.attachForm(self.radioActiveInfluences, None, 0, None, 90) form.attachControl(self.radioActiveInfluences, self.radioAllInfluences, 0, None, None, None) return result def clearNameFilter(self, *args): self.influenceNameFilter.setValue('') self.influenceNameFilter.changeCommand.emit() def radioAllInfluencesChanged(self): self.parent.updateInfluenceMenuValues() self.filterChanged.emit() def setVisible(self, visible): self.isVisible.set(visible) cmds.frameLayout(self.mainLayout, e=True, collapse=self.isVisible.get()) def toggle(self): self.setVisible(not self.isVisible.get()) def createNameFilter(self): ''' returns name filter (InflFilterMatch instance) based on control values ''' filter = InfluenceNameFilter() filter.setFilterString(self.influenceNameFilter.getValue()) return filter
def __init__(self, uiCommand=None, annotation=''): BaseUIWrapper.__init__(self, uiCommand, annotation) self.valueKeyName = 'value' self.changeCommand = Signal("ValueUIWrapper changeCommand")
class InfluencesMappingPreview(object): VAR_PREFIX = "ngSkinToolsInfluenceSourceDestinationPreview" def __init__(self): self.items = [] # type: list[InfluencesListEntry] self.mirrorMode = False self.mapper = None # type: InfluenceMapping self.currentInfluencesSelection = [] self.onDelete = Signal("influence mapping preview: onDelete") def constructInfluenceList(self): self.items = [] self.currentInfluencesSelection = [] mapper = self.mapper unmatchedSources = mapper.sourceInfluences[:] unmatchedDestinations = mapper.destinationInfluences[:] sourceInfluencesMap = dict((i.logicalIndex, i) for i in mapper.sourceInfluences) destinationInfluencesMap = dict((i.logicalIndex, i) for i in mapper.destinationInfluences) def isSourceAutomatic(src): return src.logicalIndex not in mapper.manualOverrides.keys() for source, destination in mapper.mapping.items(): source = sourceInfluencesMap[source] destination = None if destination is None else destinationInfluencesMap[destination] if source is None or destination is None: continue if source in unmatchedSources: unmatchedSources.remove(source) if destination in unmatchedDestinations: unmatchedDestinations.remove(destination) automatic = isSourceAutomatic(source) item = None if self.mirrorMode and destination is not None: item = self.findAssociation(self.items, destination.path, source.path, automatic) if item is not None: item.bidirectional = True else: item = InfluencesListEntry() item.targetAndDestinationIsSameMesh = self.mirrorMode item.source = source item.destination = destination item.bidirectional = False self.items.append(item) item.automatic = automatic self.items = sorted(self.items, influencesListSort) if len(unmatchedSources) > 0 and not self.mirrorMode: self.items.append(InfluencesListEntry(specialValue="Unmatched source influences:")) for source in unmatchedSources: self.items.append(InfluencesListEntry(source=source, automatic=isSourceAutomatic(source))) if len(unmatchedDestinations) > 0 and not self.mirrorMode: self.items.append(InfluencesListEntry(specialValue="Unmatched destination influences:")) for destination in unmatchedDestinations: self.items.append(InfluencesListEntry(destination=destination)) cmds.textScrollList(self.influencesList, e=True, removeAll=True, append=[i.asLabel() for i in self.items]) @staticmethod def findAssociation(itemList, source, destination, automatic): for i in itemList: if i.automatic != automatic: continue if i.source.path == source and i.destination.path == destination: return i if i.bidirectional and i.destination.path == source and i.source.path == destination: return i return None def getSelectedPairs(self): selection = cmds.textScrollList(self.influencesList,q=True,sii=True) if selection is not None: for i in selection: yield self.items[i-1] # noinspection PyUnusedLocal def onInfluenceSelected(self, *args): newSelection = list(self.getSelectedPairs()) newHighlight = [] for i in newSelection: if i.source is not None: newHighlight.append(i.source.path) if i.destination is not None: newHighlight.append(i.destination.path) SelectHelper.replaceHighlight(newHighlight) # the weird way of forming this currentInfluencesSelection like that # is because we want the items to be ordered in first to last selected order # when new selection happens, first all items that are not selected anymore # are removed from the current selection cache, # then all new items that are selected are added at the end. for i in self.currentInfluencesSelection[:]: if i not in newSelection: self.currentInfluencesSelection.remove(i) for i in newSelection: if i not in self.currentInfluencesSelection: self.currentInfluencesSelection.append(i) def createUI(self, parent): influencesLayout = cmds.columnLayout(parent=parent, adjustableColumn=1, rowSpacing=Constants.MARGIN_SPACING_VERTICAL) cmds.text(parent=influencesLayout, label="Influence mapping to be used:", align='left') self.influencesList = cmds.textScrollList(parent=influencesLayout, height=200, numberOfRows=5, allowMultiSelection=True, selectCommand=self.onInfluenceSelected, deleteKeyCommand=lambda *args: self.onDelete.emit())
class InfluencesManualMapping(object): VAR_PREFIX = "ngSkinToolsInfluencesManualMapping" def __init__(self): self.mirrorMode = False self.getSelectedInfluences = lambda: None self.manualOverrides = {} self.manualOverridesChanged = Signal( "influences manual mapping: manual overrides changed") def createUI(self, parent): cmds.rowLayout(parent=parent, nc=3) buttonWidth = 110 cmds.button( 'Disconnect link', width=buttonWidth, command=lambda *args: self.doDisconnectMapping(), annotation= 'Disconnect two associated influences, and make each influence point to itself' ) if self.mirrorMode: cmds.button( 'Link, both ways', width=buttonWidth, command=lambda *args: self.doConnectMapping(bidirectional=True ), annotation= 'Connect two selected influences and link them both ways') cmds.button( 'Link, one way' if self.mirrorMode else "Link", width=buttonWidth, command=lambda *args: self.doConnectMapping(bidirectional=False), annotation= 'Connect two selected influences and link on source to destination' ) cmds.rowLayout(parent=parent, nc=2) cmds.button( 'Remove manual rule', width=buttonWidth, command=lambda *args: self.removeSelectedManualMappings(), annotation= 'Remove manual rule; influence will be a subject to automatic matching' ) def addManualInfluenceMapping(self, source, destination): self.manualOverrides[ source. logicalIndex] = None if destination is None else destination.logicalIndex def doDisconnectMapping(self): for mapping in self.getSelectedInfluences(): if mapping.source is None: continue if mapping.destination is None: continue if mapping.source == mapping.destination: continue # for both source and destination, create a mapping for just itself self.addManualInfluenceMapping( mapping.source, mapping.source if mapping.targetAndDestinationIsSameMesh else None) if mapping.bidirectional: self.addManualInfluenceMapping(mapping.destination, mapping.destination) self.manualOverridesChanged.emit() def doConnectMapping(self, bidirectional=True): selection = self.getSelectedInfluences() if len(selection) < 2: return if bidirectional and len(selection) != 2: return validSources = [] for item in selection[:-1]: if item.isConnectedElsewhere() or item.source is None: continue validSources.append(item) # second selected list item destinationItem = selection[-1] if destinationItem.isConnectedElsewhere(): return destination = destinationItem.destination if destinationItem.destination is not None else destinationItem.source if destination is None: return destination = destination.logicalIndex for sourceItem in validSources: source = sourceItem.source.logicalIndex self.manualOverrides[source] = destination if bidirectional: self.manualOverrides[destination] = source self.manualOverridesChanged.emit() def removeSelectedManualMappings(self): selection = self.getSelectedInfluences() for item in selection: if item.source.logicalIndex in self.manualOverrides: del self.manualOverrides[item.source.logicalIndex] if item.bidirectional and item.destination.logicalIndex in self.manualOverrides: del self.manualOverrides[item.destination.logicalIndex] self.manualOverridesChanged.emit()
def __init__(self): self.mirrorMode = False self.getSelectedInfluences = lambda: None self.manualOverrides = {} self.manualOverridesChanged = Signal( "influences manual mapping: manual overrides changed")
def __init__(self,parent): self.parent = parent self.mainLayout = None self.filterChanged = Signal("Influence filter changed") self.isVisible = PersistentValueModel(Options.VAR_OPTION_PREFIX+"_InfluenceFilterVisible", False)
def __init__(self, ownerUI): self.ownerUI = ownerUI self.onExecuted = Signal("action executed") self.updateControls = []
class FloatSliderField: """ Similar to float slider group, only without caption """ def __init__(self, range=[0.0, 1.0]): assert len(range) == 2 self.model = None self.floatField = None self.slider = None self.onChange = Signal() self.onChanging = Signal() self.range = range self.flexibleRange = False def updateModel(self): if self.model is not None: self.model.set(self.getValue()) def sliderChanging(self, *args): """ handler for when float slider value is dragged """ self.floatField.setValue(cmds.floatSlider(self.slider, q=True, value=True)) self.updateModel() self.onChanging.emit() def sliderChanged(self, *args): self.updateModel() self.onChange.emit() def __updateSliderValue(self): value = self.floatField.getValue() minValue = cmds.floatSlider(self.slider, q=True, minValue=True) maxValue = cmds.floatSlider(self.slider, q=True, maxValue=True) if self.flexibleRange: # change min/max, if needed cmds.floatSlider(self.slider, e=True, minValue=min(value, minValue), maxValue=max(value, maxValue)) else: # change value, if needed value = min(maxValue, max(value, minValue)) cmds.floatSlider(self.slider, e=True, value=self.floatField.getValue()) def fieldChanged(self): """ handler for when float field value changes """ self.__updateSliderValue() self.updateModel() self.onChange.emit() def create(self): result = self.mainLayout = cmds.rowLayout(nc=2, adjustableColumn=2) step = (self.range[1] - self.range[0]) / 100.0 self.floatField = FloatField(self.model, step=step) if not self.flexibleRange: self.floatField.editUI(minValue=self.range[0], maxValue=self.range[1]) self.floatField.changeCommand.addHandler(self.fieldChanged) self.slider = cmds.floatSlider( value=self.floatField.getValue(), dragCommand=self.sliderChanging, changeCommand=self.sliderChanged, step=step, minValue=self.range[0], maxValue=self.range[1], ) self.__updateSliderValue() return result def setModel(self, model): self.floatField.setModel(model) self.__updateSliderValue() def setValue(self, value): self.floatField.setValue(value) self.__updateSliderValue() def getValue(self): return self.floatField.getValue() def setEnabled(self, enabled): cmds.layout(self.mainLayout, e=True, enable=enabled)
def __init__(self, ownerUI): self.ownerUI = ownerUI self.onExecuted = Signal("influence filter visibility changed") self.updateControls = []
def __init__(self,uiCommand=None,annotation=''): BaseUIWrapper.__init__(self,uiCommand,annotation) self.valueKeyName = 'value' self.changeCommand = Signal()
class InfluenceFilterUi: VAR_PREFIX = 'ngSkinToolsInfluenceFilter_' def __init__(self,parent): self.parent = parent self.mainLayout = None self.filterChanged = Signal("Influence filter changed") self.isVisible = PersistentValueModel(Options.VAR_OPTION_PREFIX+"_InfluenceFilterVisible", False) def createUI(self,parent): result = group = self.mainLayout = cmds.frameLayout(parent=parent,label="Influence Filter", marginWidth=Constants.MARGIN_SPACING_HORIZONTAL,marginHeight=Constants.MARGIN_SPACING_VERTICAL, collapsable=True, expandCommand=self.isVisible.save,collapseCommand=self.isVisible.save, borderStyle='etchedIn') cmds.frameLayout(group,e=True,collapse = self.isVisible.get()) column = cmds.columnLayout(parent=group,adjustableColumn=1,rowSpacing=Constants.MARGIN_SPACING_VERTICAL) form = FormLayout(parent=column) label=cmds.text(label='Influence Filter:') textField = self.influenceNameFilter = TextEdit(annotation="Filter influence list by name") clearButton = cmds.button(label='clear',width=50,command=self.clearNameFilter) form.attachForm(label, 10, None, 0, Constants.MARGIN_SPACING_HORIZONTAL) form.attachForm(clearButton, 10, Constants.MARGIN_SPACING_HORIZONTAL, 0, None) form.attachForm(textField,10,None,0,None) form.attachControl(textField,label,None,None,None,Constants.MARGIN_SPACING_HORIZONTAL) form.attachControl(textField,clearButton,None,Constants.MARGIN_SPACING_HORIZONTAL,None,None) textField.changeCommand.addHandler(self.filterChanged.emit) cmds.setParent(result) cmds.radioCollection() form = FormLayout(parent=column) self.radioAllInfluences = RadioButtonField(self.VAR_PREFIX+"allInfluences",defaultValue=1,label='Show all influences') self.radioAllInfluences.changeCommand.addHandler(self.radioAllInfluencesChanged) self.radioActiveInfluences = RadioButtonField(self.VAR_PREFIX+"activeInfluences",defaultValue=0,label='Only influences with non-zero weights') form.attachForm(self.radioAllInfluences, 0, 0, None, 90) form.attachForm(self.radioActiveInfluences, None, 0, None, 90) form.attachControl(self.radioActiveInfluences, self.radioAllInfluences, 0, None, None, None) return result def clearNameFilter(self,*args): self.influenceNameFilter.setValue('') self.influenceNameFilter.changeCommand.emit() def radioAllInfluencesChanged(self): self.parent.updateInfluenceMenuValues() self.filterChanged.emit() def setVisible(self,visible): self.isVisible.set(visible) cmds.frameLayout(self.mainLayout,e=True,collapse = self.isVisible.get()) def toggle(self): self.setVisible(not self.isVisible.get()) def createNameFilter(self): ''' returns name filter (InflFilterMatch instance) based on control values ''' filter = InfluenceNameFilter() filter.setFilterString(self.influenceNameFilter.getValue()) return filter
class FloatSliderField: ''' Similar to float slider group, only without caption ''' def __init__(self, range=(0.0, 1.0)): assert (len(range) == 2) self.model = None self.floatField = None self.slider = None self.onChange = Signal("floatSliderChange") self.onChanging = Signal("floatSliderChanging") self.range = range self.flexibleRange = False def updateModel(self): if self.model is not None: self.model.set(self.getValue()) def sliderChanging(self, *args): ''' handler for when float slider value is dragged ''' self.floatField.setValue( cmds.floatSlider(self.slider, q=True, value=True)) self.updateModel() self.onChanging.emit() def sliderChanged(self, *args): self.updateModel() self.onChange.emit() def __updateSliderValue(self): value = self.floatField.getValue() minValue = cmds.floatSlider(self.slider, q=True, minValue=True) maxValue = cmds.floatSlider(self.slider, q=True, maxValue=True) if self.flexibleRange: #change min/max, if needed cmds.floatSlider(self.slider, e=True, minValue=min(value, minValue), maxValue=max(value, maxValue)) else: #change value, if needed value = min(maxValue, max(value, minValue)) cmds.floatSlider(self.slider, e=True, value=self.floatField.getValue()) def fieldChanged(self): ''' handler for when float field value changes ''' self.__updateSliderValue() self.updateModel() self.onChange.emit() def create(self): result = self.mainLayout = cmds.rowLayout(nc=2, adjustableColumn=2) step = (self.range[1] - self.range[0]) / 100.0 self.floatField = FloatField(self.model, step=step) if not self.flexibleRange: self.floatField.editUI(minValue=self.range[0], maxValue=self.range[1]) self.floatField.changeCommand.addHandler(self.fieldChanged) self.slider = cmds.floatSlider(value=self.floatField.getValue(), dragCommand=self.sliderChanging, changeCommand=self.sliderChanged, step=step, minValue=self.range[0], maxValue=self.range[1]) self.__updateSliderValue() return result def setModel(self, model): self.floatField.setModel(model) self.__updateSliderValue() def setValue(self, value): self.floatField.setValue(value) self.__updateSliderValue() def getValue(self): return self.floatField.getValue() def setEnabled(self, enabled): cmds.layout(self.mainLayout, e=True, enable=enabled)
class TreeViewIDList: def __init__(self,allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand if Utils.getMayaVersion()<Utils.MAYA2012: selectCommand = Utils.createMelProcedure(self.selectionChanged, [('int','item'),('int','state')],returnType="int") editCommand = Utils.createMelProcedure(self.editLabelCommand, [('string','item'),('string','newName')]) self.control = cmds.treeView(numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand) if Utils.getMayaVersion()>=Utils.MAYA2011: cmds.treeView(self.control,e=True,enableKeys=True) self.selectedID = None self.selectedItems = set() self.onSelectionChanged = Signal() self.__selectionChanging = False self.__itemNameChanging = False def setItems(self,newItems,selectedID=None): if selectedID is None: selectedID = self.getSelectedID() if self.items!=newItems: self.doSetItems(newItems) self.items = newItems self.selectByID(selectedID) def selectionChanged(self,item,selected): self.__selectionChanging = True try: selected = int(selected) item = int(item) if selected: self.selectedItems.add(item) self.selectedID = item self.onSelectionChanged.emit() else: self.selectedItems.discard(item) finally: self.__selectionChanging = False return True def internalEditLabelCommand(self,item,newName): ''' indirectly executed by treeview inplace editor; return non empty string to let treeView know that rename succeeded ''' return '' def editLabelCommand(self,item,newName): ''' subclasses should override internalEditLabelCommand instead ''' self.__itemNameChanging = True try: return self.internalEditLabelCommand(item, newName) finally: self.__itemNameChanging = False def doSetItems(self,newItems): if self.__selectionChanging: raise Exception("cannot change items while selection is changing") if self.__itemNameChanging: # raise Exception("cannot change items while item name is changing") # silently exit: should be no harm ignoring new items as the only thing that changed # is label name, and we already reflect that in UI return self.selectedID = None self.selectedItems.clear() #cmds.treeView(self.control,e=True,clearSelection=True) cmds.treeView(self.control,e=True,removeAll=True) for i in newItems: cmds.treeView(self.control,e=True,addItem=(i.id,'')) cmds.treeView(self.control,e=True,displayLabel=(i.id,i.displayName),displayLabelSuffix=(i.id,i.suffix)) def getSelectedID(self): return self.selectedID def getSelectedNames(self): return [i.name for i in self.items if (i.id in self.selectedItems)] def getSelectedIDs(self): return list(self.selectedItems) def selectByID(self,id): if self.__selectionChanging: return if self.selectedID==id: return self.selectedItems.add(id) for i in self.items: cmds.treeView(self.control,e=True,si=(i.id,int(i.id==id)))
class TreeViewIDList(object): def __init__(self, allowMultiSelection=True): self.items = [] selectCommand = self.selectionChanged editCommand = self.editLabelCommand self.control = cmds.treeView( numberOfButtons=0, height=100, selectCommand=selectCommand, editLabelCommand=editCommand, dragAndDropCommand=self.handleDragDropCommand) cmds.treeView(self.control, e=True, enableKeys=True) # list of selected IDs self.selectedItems = [] self.onSelectionChanged = Signal("onSelectionChanged") self.__selectionChanging = False self.__itemNameChanging = False def handleDragDropCommand(self, itemList, prevParents, prevIndexes, newParent, newIndexes, itemBefore, itemAfter): pass def setItems(self, newItems, selectedID): ''' sets new items in the ID list; :param list newItems: list of IdToNameEntry :param selectedID: item to select in the list after setting the items ''' collapsedItems = set( [item.id for item in self.items if self.isCollapsed(item.id)]) if self.items != newItems: if self.__selectionChanging: raise Exception( "cannot change items while selection is changing") if self.__itemNameChanging: # raise Exception("cannot change items while item name is changing") # silently exit: should be no harm ignoring new items as the only thing that changed # is label name, and we already reflect that in UI return self.selectedItems = [] cmds.treeView(self.control, e=True, clearSelection=True) cmds.treeView(self.control, e=True, removeAll=True) for i in newItems: cmds.treeView( self.control, e=True, addItem=(i.id, "" if i.parent is None else str(i.parent))) cmds.treeView(self.control, e=True, displayLabel=(i.id, i.displayName), displayLabelSuffix=(i.id, i.suffix), expandItem=(i.id, i.id not in collapsedItems)) self.items = newItems self.selectByID(selectedID) def selectionChanged(self, itemId, selected): ''' UI event handler for when selection is changed there are events fired for items being unselected (``selected`` is 0) and for items being selected (``selected`` is 1) ''' self.__selectionChanging = True try: if selected: if itemId is not None and itemId not in self.selectedItems: self.selectedItems.append(itemId) self.onSelectionChanged.emit() else: if itemId in self.selectedItems: self.selectedItems.remove(itemId) self.onSelectionChanged.emit() finally: self.__selectionChanging = False return True def internalEditLabelCommand(self, item, newName): ''' indirectly executed by treeview inplace editor; return non empty string to let treeView know that rename succeeded :return: True, if rename was successful; false otherwise. ''' return False def editLabelCommand(self, itemId, newName): ''' UI event handler for when user edits item label; subclasses should override internalEditLabelCommand instead ''' self.__itemNameChanging = True try: renameSuccessful = self.internalEditLabelCommand(itemId, newName) if not renameSuccessful: return '' return itemId finally: self.__itemNameChanging = False def getSelectedNames(self): ''' :return: names of all currently selected items ''' return [i.name for i in self.items if (i.id in self.selectedItems)] def getSelectedID(self): ''' :return: ID of currently selected item ''' return None if not self.selectedItems else self.selectedItems[-1] def getSelectedIDs(self): ''' :return: IDs of selected items ''' return self.selectedItems def selectByID(self, itemId): self.setSelectedIDs([itemId]) def setSelectedIDs(self, ids): log.debug("selecting by IDs: {0}".format(ids)) if self.__selectionChanging: return # remove any null items ids = [str(i) for i in ids if i is not None] if self.selectedItems == ids: return self.selectedItems = ids for i in self.items: cmds.treeView(self.control, e=True, si=(i.id, int(i.id in ids))) def setCollapsed(self, itemId, isCollapsed): cmds.treeView(self.control, e=True, expandItem=(itemId, not isCollapsed)) def isCollapsed(self, itemId): return not cmds.treeView(self.control, q=True, isItemExpanded=itemId)