import maya.cmds as mc import maya.OpenMayaUI as omui import maya.api.OpenMaya as om import math try: from PySide import QtCore, QtWidgets, QtGui from shiboken import wrapInstance except: from PySide2 import QtCore, QtWidgets, QtGui from shiboken2 import wrapInstance BEND_TASK_NUM = 1 #BENDBOW default values BB_NAME = 'Bendbow_' RIBBION_NAME = 'bind' NUM_JOINTS = 5 DEFAULT_RAD = 2 def getMayaWindow(): pointer = omui.MQtUtil.mainWindow() if pointer is not None: return wrapInstance(int(pointer), QtWidgets.QWidget)#int should be long, but for some reason It doesn't work :/ def gui_makeHorizontalLayout(widgets, margins=None, ratio=None): horizLayout = QtWidgets.QHBoxLayout() for i,wid in enumerate(widgets): if ratio: horizLayout.addWidget(wid, ratio[i]) else: horizLayout.addWidget(wid) if margins: horizLayout.setContentsMargins(margins[0],margins[1],margins[2],margins[3]) return horizLayout def gui_makeVerticalLayout(widgets, margins=None, ratio=None): vertLayout = QtWidgets.QVBoxLayout() for i,wid in enumerate(widgets): if ratio: vertLayout.addWidget(wid, ratio[i]) else: vertLayout.addWidget(wid) if margins: vertLayout.setContentsMargins(margins[0],margins[1],margins[2],margins[3]) return vertLayout class BendBow(): def __init__(self, bBname, bindname, anchorA, anchorB, divs): self.nurbsLength = self.getDistance(anchorA, anchorB) self.bendBowTrans, self.bendBowRot = self.midpoint(anchorA, anchorB) self.bendbowDivJoints = divs self.bendbowName = bBname self.bindName = bindname self.trg_ctrls = [] self.bindLoc_list = [] self.bindJnts_list = [] self.bindJntRad = 0.5 self.the_bendbow = self.makeBendBow() tr = self.bendBowTrans rot = self.bendBowRot mc.select( clear=True ) mc.setAttr(self.the_bendbow+'.translate', tr[0], tr[1], tr[2]) mc.setAttr(self.the_bendbow+'.rotate', rot[0], rot[1], rot[2]) #object a is start and object b is end def getDistance(self, objA, objB): gPA = om.MPoint(mc.xform(objA, q=True, t=True, ws=True)) gPB = om.MPoint(mc.xform(objB, q=True, t=True, ws=True)) return om.MVector(gPB-gPA).length() def getObjWorldOrient(self, Obj, lookAtVector): pwm = om.MMatrix(mc.getAttr(Obj+'.worldMatrix')) #-90 degree rotation rotright = om.MMatrix([0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]) prod = rotright * pwm new_z = om.MVector([prod[8], prod[9], prod[10]]) add_rot_M = om.MQuaternion(new_z,lookAtVector,factor=1.0).asMatrix() tMat = om.MTransformationMatrix(prod*add_rot_M) # eulerRotation is a MEulerRotation object eulerRot = tMat.rotation(asQuaternion=False) angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)] return angles def midpoint(self, objA, objB): gPA = om.MPoint(mc.xform(objA, q=True, t=True, ws=True)) gPB = om.MPoint(mc.xform(objB, q=True, t=True, ws=True)) lenVect = om.MVector(gPB-gPA) midP = gPA+(lenVect*0.5) #if first anchor is joint, return same orientation #else return orientation of vector between two anchors #print('objectA is of type: '+str(mc.objectType(objA))) angles = [] if mc.objectType(objA) == 'joint': angles = self.getObjWorldOrient(objA, lenVect) else: gRot = om.MQuaternion(om.MVector(0,0,1),lenVect,factor=1.0).asEulerRotation() angles = [math.degrees(angle) for angle in (gRot.x, gRot.y, gRot.z)] return [midP[0], midP[1], midP[2]], angles def overrideColor(self, shape, color): mc.select(shape, vis=True) mc.setAttr(shape+'Shape.overrideEnabled', 1) mc.setAttr(shape+'Shape.overrideColor', color) def makeControlJoints(self): trg1 = mc.joint(p=[0,0,self.nurbsLength/2], n=self.bindName+'_ctrl_joint1') t1 = mc.ls(trg1, long=True) mc.select(cl=True) trg2 = mc.joint(p=[0,0,0], n=self.bindName+'_ctrl_joint2') t2 = mc.ls(trg2, long=True) mc.select(cl=True) trg3 = mc.joint(p=[0,0,-self.nurbsLength/2], n=self.bindName+'_ctrl_joint3') t3 = mc.ls(trg3, long=True) mc.select(cl=True) #self.trg_ctrls=[t1[0], t2[0], t3[0]] self.trg_ctrls=[trg1, trg2, trg3] print(self.trg_ctrls) #print(t1,t2,t3) print('______________________________') def makeBindJoints(self): for i in range(self.bendbowDivJoints): ord_num = ("%%0%si" % len(str(self.bendbowDivJoints))) % int(i+1) self.bindLoc_list.append(mc.spaceLocator(p=[0,0,0], n=self.bindName+'_loc_'+ord_num)[0])#take note of later self.bindJnts_list.append(mc.joint(p=[0,0,0], rad=self.bindJntRad, n=self.bindName+'_joint'+ord_num)) mc.select(cl=True) def makePointOnSurfaceNodes(self, ribbonBind): for i, loca in enumerate(self.bindLoc_list): loc = self.bendbowName+loca.split('|')[-1] ord_num = ("%%0%si" % len(str(self.bendbowDivJoints))) % int(i+1) point1 = mc.createNode('pointOnSurfaceInfo', n=loc+'_pointOnSurfaceInfo_'+ord_num) mc.connectAttr(ribbonBind+'Shape.worldSpace[0]', point1+'.inputSurface') mc.setAttr(point1+'.parameterU', 0.5) mc.setAttr(point1+'.parameterV', (i)/(self.bendbowDivJoints-1)) fourMat1 = mc.createNode ('fourByFourMatrix', n=loc+'_fourByFourMatrix_' +ord_num) mc.connectAttr(point1+'.normalizedNormalX', fourMat1+'.in00') mc.connectAttr(point1+'.normalizedNormalY', fourMat1+'.in01') mc.connectAttr(point1+'.normalizedNormalZ', fourMat1+'.in02') mc.connectAttr(point1+'.normalizedTangentVX', fourMat1+'.in10') mc.connectAttr(point1+'.normalizedTangentVY', fourMat1+'.in11') mc.connectAttr(point1+'.normalizedTangentVZ', fourMat1+'.in12') mc.connectAttr(point1+'.normalizedTangentUX', fourMat1+'.in20') mc.connectAttr(point1+'.normalizedTangentUY', fourMat1+'.in21') mc.connectAttr(point1+'.normalizedTangentUZ', fourMat1+'.in22') mc.connectAttr(point1+'.positionX', fourMat1+'.in30') mc.connectAttr(point1+'.positionY', fourMat1+'.in31') mc.connectAttr(point1+'.positionZ', fourMat1+'.in32') decomp1 = mc.createNode ('decomposeMatrix', n=loc+'_decomposeMatrix_'+ord_num) mc.connectAttr(fourMat1+'.output', decomp1+'.inputMatrix') mc.connectAttr(decomp1+'.outputTranslate', loca+'.translate') mc.connectAttr(decomp1+'.outputRotate', loca+'.rotate') def makeBendBow(self): ribbon = mc.nurbsPlane (d=2, u=1, v=2,ax=[0,1,0], lr=self.nurbsLength, n=self.bendbowName+'_'+self.bindName+'_ribbon') globalCtrl = mc.circle(c=[0,0,0], nr=[0,0,1], r=1, d=1, s=4, n=self.bendbowName+'_globalCtrl') self.overrideColor(globalCtrl[0], 15) self.makeControlJoints() self.makeBindJoints() #group hirarchy _ Emily's script bendBowGrp = mc.group(em=True, n=self.bendbowName) offsetGrp = mc.group(em=True, p=bendBowGrp, n=self.bendbowName+'_grp_OFFSET') ctrlGrp = mc.group(em=True, p=offsetGrp, n=self.bendbowName+'_ctrl_grp') mc.parent(globalCtrl[0], ctrlGrp) inCtrl = mc.group(em=True, p=globalCtrl[0], n=self.bindName+'_bendbow') ctrlJntGrp = mc.group(em=True, p=inCtrl, n=self.bindName+'_ctrl_jnt_grp') bindJntGrp = mc.group(em=True, p=inCtrl, n=self.bindName+'_bind_jnt_grp') mc.setAttr(bindJntGrp+'.inheritsTransform', 0) #parenting elements _ Emily's script mc.select(ribbon, vis=True) ribbonSelect = mc.ls(selection=True) ribbonBind = ribbonSelect[0] mc.parent(ribbonBind, inCtrl) for i,trg in enumerate(self.trg_ctrls): n_trg = mc.parent(trg, ctrlJntGrp)[0] self.trg_ctrls[i] = mc.ls(n_trg, long=True)[0] #self.trg_ctrls[i] = mc.parent(trg, ctrlJntGrp)[0] print(self.trg_ctrls) for i,bindLoc in enumerate(self.bindLoc_list): self.bindLoc_list[i] = mc.parent(bindLoc, bindJntGrp)[0] #ribbon construction _ Emily's script mc.setAttr(ribbonBind+'.inheritsTransform',0) ribbonSkin = mc.skinCluster(self.trg_ctrls[0], self.trg_ctrls[1], self.trg_ctrls[2], ribbonBind, bm=0, dr=4.5, n=self.bindName+'_skinCluster') mc.skinPercent (ribbonSkin[0], ribbonBind+'.cv[0:2][2]', tv = [self.trg_ctrls[1], 1.0]) mc.skinPercent (ribbonSkin[0], ribbonBind+'.cv[0:2][1]', tv = [self.trg_ctrls[1], 1.0]) self.makePointOnSurfaceNodes(ribbonBind) return bendBowGrp def getTrg_ctrls_list(self): return self.trg_ctrls class NumberSlider(object): def __init__(self): self.sliderWidget = QtWidgets.QWidget() hbox = QtWidgets.QHBoxLayout() self.slider = QtWidgets.QSlider() self.slider.setOrientation(QtCore.Qt.Horizontal) self.slider.setTickPosition(QtWidgets.QSlider.TicksBelow) self.slider.setTickInterval(10) self.slider.setMinimum(3) self.slider.setMaximum(100) self.slider.valueChanged.connect(self.changedValue) self.label = QtWidgets.QLabel("0") self.label.setFont(QtGui.QFont("Sanserif", 15)) hbox.addWidget(self.slider) hbox.addWidget(self.label) self.sliderWidget.setLayout(hbox) def changedValue(self): size = self.slider.value() print('hello!: '+str(size)) self.label.setText(str(size)) def getWidget(self): return self.sliderWidget class Header(QtWidgets.QWidget): def __init__(self, name, content_widget, textBold=True, tabHeight = 1.5, hasColor=True): super(Header, self).__init__() self.content = content_widget self.expand_ico = QtGui.QPixmap(":teDownArrow.png") self.collapse_ico = QtGui.QPixmap(":teRightArrow.png") stacked = QtWidgets.QStackedLayout(self) stacked.setStackingMode(QtWidgets.QStackedLayout.StackAll) background = QtWidgets.QLabel() if hasColor: background.setStyleSheet("QLabel{ background-color: rgb(93, 93, 93); border-radius:2px};") else: background.setStyleSheet("QLabel{ border-radius:2px};") widget = QtWidgets.QWidget() layout = QtWidgets.QHBoxLayout(widget) self.icon = QtWidgets.QLabel() self.icon.setPixmap(self.expand_ico) layout.addWidget(self.icon) layout.setContentsMargins(11, 0, 11, 0) font = QtGui.QFont() font.setBold(textBold) label = QtWidgets.QLabel(name) label.setFont(font) layout.addWidget(label) layout.addItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)) stacked.addWidget(widget) stacked.addWidget(background) background.setMinimumHeight(layout.sizeHint().height() * tabHeight) def mousePressEvent(self, *args): self.expand() if not self.content.isVisible() else self.collapse() def expand(self): self.content.setVisible(True) self.icon.setPixmap(self.expand_ico) def collapse(self): self.content.setVisible(False) self.icon.setPixmap(self.collapse_ico) class Container(QtWidgets.QWidget): def __init__(self, name, color_background=False, textBold=True, tabHeight=1.5, hasColor=True): super(Container, self).__init__() layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self._content_widget = QtWidgets.QWidget() if color_background: self._content_widget.setStyleSheet(".QWidget{background-color: rgb(73, 73, 73); " "margin-left: 2px; margin-right: 2px}") header = Header(name, self._content_widget, textBold, tabHeight, hasColor) layout.addWidget(header) layout.addWidget(self._content_widget) # assign header methods to instance attributes so they can be called outside of this class self.collapse = header.collapse self.expand = header.expand self.toggle = header.mousePressEvent @property def contentWidget(self): """Getter for the content widget Returns: Content widget """ return self._content_widget class BendBowTask(): def __init__(self, bBName, ribbonname, anchorA, anchorB, num_joints): self.bendbowName = bBName self.ribbonName = ribbonname self.startAnchor = anchorA self.endAnchor = anchorB self.numberOfJoints = num_joints def makeBendbowTaskPannel(self): widget_Task = QtWidgets.QWidget() widget_LeftPannel = self.bendbowTaskLeftPannel() widget_editTask = self.bendbowTaskRightPannel() horizLayout = gui_makeHorizontalLayout([widget_LeftPannel, widget_editTask], ratio=[3,7]) horizLayout.setContentsMargins(0,0,0,0) widget_Task.setLayout(horizLayout) return widget_Task def bendbowTaskRightPannel(self): widget_editTask = QtWidgets.QWidget() widget_nameWidget = QtWidgets.QWidget() label_nameInd = QtWidgets.QLabel('Bendbow name: ') self.taskName_textbox = QtWidgets.QLineEdit()#Bendbow name self.taskName_textbox.setText(self.bendbowName) layout_horzName = gui_makeHorizontalLayout([label_nameInd, self.taskName_textbox], margins=[0,0,0,0]) widget_nameWidget.setLayout(layout_horzName) container_vars = Container("Edit variables", textBold=False, tabHeight=0.75, hasColor=False) container_vars.collapse() content_layout = QtWidgets.QGridLayout(container_vars.contentWidget) #EXTRA VARIABLES ------ widget_varsWidget = QtWidgets.QWidget() widget_ribName = QtWidgets.QWidget() label_ribName = QtWidgets.QLabel('Ribbon name: ') self.textbox_ribName = QtWidgets.QLineEdit()#Ribbon name self.textbox_ribName.setText(self.ribbonName) layout_ribName = gui_makeHorizontalLayout([label_ribName, self.textbox_ribName], margins=[0,0,0,0], ratio=[2,8]) widget_ribName.setLayout(layout_ribName) widget_ctrlName = QtWidgets.QWidget() label_ctrlName = QtWidgets.QLabel('Control name: ') self.textbox_ctrlName = QtWidgets.QLineEdit()#Control name self.textbox_ctrlName.setText(self.bendbowName+'_Ctrl') #connecting to Bendbow name textbox in case the name changes self.taskName_textbox.textChanged[str].connect(self.onTextChanged) label_ctrlRadius = QtWidgets.QLabel(' radius: ') self.textbox_ctrlRadius= QtWidgets.QLineEdit(str(DEFAULT_RAD)) onlyInt = QtGui.QIntValidator() self.textbox_ctrlRadius.setValidator(onlyInt) layout_ctrlName = gui_makeHorizontalLayout([label_ctrlName, self.textbox_ctrlName, label_ctrlRadius, self.textbox_ctrlRadius], margins=[0,0,0,0], ratio=[2,6,1,1]) widget_ctrlName.setLayout(layout_ctrlName) widget_numJoints = QtWidgets.QWidget() label_numJoints = QtWidgets.QLabel('Bind Joints: ') #self.slider1 = NumberSlider() #self.sliderWidget1 = self.slider1.getWidget() slider_widget, self.label_number = self.createSliderWidget() # number slider #slider_numJoints.valueChanged.connect(self.changeValue(label_number, slider_numJoints)) #slider_numJoints.setOrientation(QtCore.Horizontal) layout_numJoints = gui_makeHorizontalLayout([label_numJoints, slider_widget], margins=[0,0,0,0], ratio=[2,8]) widget_numJoints.setLayout(layout_numJoints) layout_vertVars = gui_makeVerticalLayout([widget_ribName, widget_ctrlName, widget_numJoints], margins=[0,0,0,0]) widget_varsWidget.setLayout(layout_vertVars) content_layout.addWidget(widget_varsWidget) #EXTRA VARIABLES ^^^^^^^ invertLayout = gui_makeVerticalLayout([widget_nameWidget, container_vars], margins=[0,0,0,0]) widget_editTask.setLayout(invertLayout) return widget_editTask def onTextChanged(self, text): self.textbox_ctrlName.setText(text+'_Ctrl') def bendbowTaskLeftPannel(self): widget_LeftPannel = QtWidgets.QWidget() label_bbjoint = QtWidgets.QLabel(str(self.startAnchor)+' > '+str(self.endAnchor)) font = QtGui.QFont() font.setBold(True) label_bbjoint.setFont(font) buffer = QtWidgets.QWidget() layout_leftPannel = gui_makeVerticalLayout([label_bbjoint], margins=[0,0,0,0]) layout_leftPannel.addWidget(buffer, stretch=2) widget_LeftPannel.setLayout(layout_leftPannel) return widget_LeftPannel def createSliderWidget(self): widget = QtWidgets.QWidget() #slider = QtWidgets.QSlider(orientation=QtCore.Qt.Horizontal) #slider.setMinimum(3) #slider.setMaximum(100) emptySpace = QtWidgets.QWidget() label = QtWidgets.QLineEdit(str(self.numberOfJoints)) onlyInt = QtGui.QIntValidator() label.setValidator(onlyInt) #label.setFont(QtGui.QFont("Sanserif", 10)) #slider->emptySpace hBox = gui_makeHorizontalLayout([label, emptySpace], margins=[0,0,0,0], ratio=[2,8]) widget.setLayout(hBox) return widget, label#slider def changeValue(self, label, slider): size = slider.value() #print('slider value:'+str(size)) label.setText(str(size)) def runBendBowTask(self, bendCornerCtrlJnts, bendMidCtrlJnts, bendEndCtrlJnts, bendBowGrp, taskNum, totalTasks): #always add ctrl joint2 to mid bendbow control #for the 1st bendbow, just add jnt1 to a list of 2 #for the 2nd-nth bendbow, add jnt3 to the last list of two and make a new list with jnt1 #for the nth bendbow, append joint3 to the last list of two bendbow = BendBow(str(self.taskName_textbox.text()), str(self.textbox_ribName.text()), str(self.startAnchor), str(self.endAnchor), int(self.label_number.text())) trg_ctrls = bendbow.getTrg_ctrls_list() print(taskNum, totalTasks) if taskNum == 0: bendEndCtrlJnts.append(trg_ctrls[2]) bendCornerCtrlJnts.append([trg_ctrls[0]]) elif taskNum < totalTasks: bendCornerCtrlJnts[taskNum-1].append(trg_ctrls[2]) bendCornerCtrlJnts.append([trg_ctrls[0]]) else: bendCornerCtrlJnts[taskNum-1].append(trg_ctrls[2]) bendEndCtrlJnts.append(trg_ctrls[0]) bendMidCtrlJnts.append(trg_ctrls[1]) bendBowGrp.append(bendbow.the_bendbow) def getBendBowCtrlNameAndRadius(self): return str(self.textbox_ctrlName.text()), str(self.textbox_ctrlRadius.text()) def toString(self): #print('BENDBOW TASK: '+str(self.bendbowName)) print('BENDBOW TASK: '+str(self.taskName_textbox.text())) #print(' bind:'+str(self.ribbonName)) print(' bind:'+str(self.textbox_ribName.text())) #print(' ctrl:'+str(self.bendbowCtrlName)) print(' ctrl:'+str(self.textbox_ctrlName.text())) print(' posA:'+str(self.startAnchor)) print(' posB:'+str(self.endAnchor)) #print(' divs:'+str(self.numberOfJoints)) print(' divs:'+str(self.label_number.text())) class JointChainBendbowContainer(): def __init__(self, jointChain): self.jointChainList = jointChain title = 'Joint Chain: ' for i, j in enumerate(jointChain): if i == 0: title = title+str(j) else: title = title+' > '+str(j) self.title = title self.theContainer = Container(self.title) self.content_layout = QtWidgets.QVBoxLayout(self.theContainer.contentWidget) self.content_layout.setContentsMargins(5,0,5,0) self.BendBowTaskList = [] self.cornerControlWidgets = [] self.bendEndCtrlJnts=[] self.bendMidCtrlJnts = [] self.bendCornerCtrlJnts = [] self.midControlNamesRads = [] self.cornerControlNamesRads = [] self.createBendBowTasks() #self.content_layout.addWidget(QtWidgets.QPushButton("Button")) def createBendBowTasks(self): global BB_NAME, BEND_TASK_NUM, RIBBION_NAME, NUM_JOINTS jointChain_range = len(self.jointChainList)-1 for i in range(jointChain_range): objA = self.jointChainList[i] objB = self.jointChainList[i+1] bbTask = BendBowTask(BB_NAME+str(BEND_TASK_NUM), RIBBION_NAME, objA, objB, NUM_JOINTS) BEND_TASK_NUM = BEND_TASK_NUM+1 self.BendBowTaskList.append(bbTask) self.content_layout.addWidget(bbTask.makeBendbowTaskPannel()) if i < jointChain_range-1: widget_ctrlName = self.cornerCtrlJntWidget(self.jointChainList[i+1]) self.content_layout.addWidget(widget_ctrlName) def cornerCtrlJntWidget(self, jnt_name): widget_cornCtrl = QtWidgets.QWidget() font = QtGui.QFont() font.setBold(True) label_ctrlName = QtWidgets.QLabel(jnt_name+' control name: ') label_ctrlName.setFont(font) textbox_ctrlName = QtWidgets.QLineEdit(jnt_name+'_Ctrl') label_ctrlRadius = QtWidgets.QLabel(' radius: ') label_ctrlRadius.setFont(font) textbox_ctrlRadius= QtWidgets.QLineEdit(str(DEFAULT_RAD)) horizLay = gui_makeHorizontalLayout([label_ctrlName,textbox_ctrlName,label_ctrlRadius,textbox_ctrlRadius], margins=[30,0,30,0], ratio=[2,6,1,1]) widget_cornCtrl.setLayout(horizLay) self.cornerControlWidgets.append([textbox_ctrlName, textbox_ctrlRadius]) return widget_cornCtrl def getWidget(self): return self.theContainer def getBendBowTaskList(self): return self.BendBowTaskList def runBendBowTaskList(self): #here make the controls or something :\ bendBowGrp = [] for i, task in enumerate(self.BendBowTaskList): task.toString() task.runBendBowTask(self.bendCornerCtrlJnts , self.bendMidCtrlJnts, self.bendEndCtrlJnts,bendBowGrp, i, len(self.BendBowTaskList)-1) self.midControlNamesRads.append(task.getBendBowCtrlNameAndRadius())# gets tuples print(' ') for bc in self.bendCornerCtrlJnts: print(bc) for widg in self.cornerControlWidgets: self.cornerControlNamesRads.append([widg[0].text(), widg[1].text()]) control_group = self.makeBendBowControls() bendBows_group = mc.group(em=True, n='BendBows_Grp_1') mc.parent(bendBowGrp, bendBows_group) def makeBendBowControls(self): corner_ctrls = [] corner_grps = [] for j, cJnt in enumerate(self.bendCornerCtrlJnts): #Make The Control ctrl = mc.circle(nr=(0,0,1) ,r=self.cornerControlNamesRads[j][1], n=self.cornerControlNamesRads[j][0]) off_grp = mc.group(ctrl, n=self.cornerControlNamesRads[j][0]+'_OFFSET') grp = mc.group(off_grp, n=self.cornerControlNamesRads[j][0]+'_Grp') mc.delete(mc.parentConstraint(cJnt[0],cJnt[1], grp)) #change mo to True if you want the joints to not snap into the middle jnt mc.parentConstraint(ctrl, cJnt[0], mo=False) mc.parentConstraint(ctrl, cJnt[1], mo=False) corner_ctrls.append(ctrl) corner_grps.append(grp) mid_grps = [] for i, midJnt in enumerate(self.bendMidCtrlJnts): #Make The Control ctrl = mc.circle(nr=(0,0,1) ,r=self.midControlNamesRads[i][1] ,n=self.midControlNamesRads[i][0]) off_grp = mc.group(ctrl, n=self.midControlNamesRads[i][0]+'_OFFSET') grp = mc.group(off_grp, n=self.midControlNamesRads[i][0]+'_Grp') #source then target mc.delete(mc.parentConstraint(midJnt, grp)) mc.parentConstraint(ctrl, midJnt, mo=True) if i == 0: mc.pointConstraint(self.bendEndCtrlJnts[0],corner_ctrls[i], grp, mo=True) mc.aimConstraint(corner_ctrls[i],grp,mo=True) elif i < len(self.bendMidCtrlJnts)-1: mc.pointConstraint(corner_ctrls[i],corner_ctrls[i-1], grp, mo=True) mc.aimConstraint(corner_ctrls[i],grp,mo=True) else: mc.pointConstraint(corner_ctrls[i-1], self.bendEndCtrlJnts[1], grp, mo=True) mc.aimConstraint(corner_ctrls[i-1],grp,mo=True) mid_grps.append(grp) control_group = mc.group(em=True, n='BendBow_Controls_Grp_1') mc.parent(mid_grps, control_group) mc.parent(corner_grps, control_group) return control_group class BendBowCreatorUI(object): def __init__(self): self.window = 'BendBowCreatorUI_uniqueId' self.title = 'Bend Bow Creator' self.size = (1000,650) self.supportsToolAction = False self.actionName = 'Create and Close' self.applyName = 'Create' self.closeName = 'Close' self.bendbowContainerList = [] def create(self): if mc.window(self.window, exists= True): mc.deleteUI(self.window ,window= True) self.parentWindow = getMayaWindow() self.mainWindow = QtWidgets.QMainWindow(self.parentWindow) self.mainWindow.setObjectName(self.window) self.mainWindow.setWindowTitle(self.title) self.mainWidget = QtWidgets.QWidget() self.mainWindow.setCentralWidget(self.mainWidget) QtWidgets.QStyleFactory.create('Windows') self.mainLayout = QtWidgets.QVBoxLayout(self.mainWidget) self.JointChainListGroup() self.ButtonsLayout() self.mainWindow.show() def ButtonsLayout(self): self.groupBox_buttons = QtWidgets.QGroupBox() self.layout_buttons = QtWidgets.QHBoxLayout() self.button_addJointChain = QtWidgets.QPushButton('Add Joint Chain') self.button_addJointChain.clicked.connect(self.button_addJointChain_onClicked) self.button_createBendBows = QtWidgets.QPushButton('Create Bend Bows') self.button_createBendBows.clicked.connect(self.button_createBendBows_onClicked) self.button_clearQueue = QtWidgets.QPushButton('Clear Queue') self.button_clearQueue.clicked.connect(self.button_clearQueue_onClicked) self.layout_buttons.addWidget(self.button_addJointChain) self.layout_buttons.addWidget(self.button_createBendBows) self.layout_buttons.addWidget(self.button_clearQueue) self.mainLayout.addWidget(self.groupBox_buttons) self.groupBox_buttons.setLayout(self.layout_buttons) def JointChainListGroup(self): groupBox_jointChainList = QtWidgets.QGroupBox('Joint Chain Catalogue:') layout_ScollChainList = QtWidgets.QVBoxLayout() self.scroll = QtWidgets.QScrollArea() content_widget = QtWidgets.QWidget() self.scroll.setWidget(content_widget) self.scroll.setWidgetResizable(True) self.layout_BufferAndWidgets = QtWidgets.QVBoxLayout(content_widget) wid_element = QtWidgets.QWidget() self.layout_CollWidgets = QtWidgets.QVBoxLayout() self.layout_CollWidgets.setContentsMargins(0,0,0,0) wid_element.setLayout(self.layout_CollWidgets) buffer = QtWidgets.QWidget() buffer.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.scroll.setMinimumHeight(270) layout_ScollChainList.addWidget(self.scroll) self.layout_BufferAndWidgets.addWidget(wid_element) self.layout_BufferAndWidgets.addWidget(buffer, stretch=2) self.mainLayout.addWidget(groupBox_jointChainList) groupBox_jointChainList.setLayout(layout_ScollChainList) def button_createBendBows_onClicked(self): for container in self.bendbowContainerList: print(container.title) container.runBendBowTaskList() self.button_clearQueue_onClicked() def button_addJointChain_onClicked(self): jointList, message = self.findJointChain() if jointList: jjc = JointChainBendbowContainer(jointList) self.bendbowContainerList.append(jjc) self.layout_CollWidgets.addWidget(jjc.getWidget()) else: mc.warning(message) def button_clearQueue_onClicked(self): #global BEND_TASK_NUM self.clearLayout(self.layout_CollWidgets) self.bendbowContainerList.clear() #BEND_TASK_NUM = 1 def clearLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.deleteLater() else: self.clearLayout(item.layout()) def findJointChain(self): ret_list = [] message = '' sel = mc.ls(sl=True) if len(sel) == 2: allDes = mc.listRelatives(sel[0], allDescendents=True) #print(allDes) allPaths = [] r_path = [] self.dfs_joint([], allPaths, [sel[0]], r_path, sel[0], sel[1]) if len(r_path) == 0: message = 'No path was found for selected joints.' else: ret_list = r_path[0] else: message = 'Please select a starting joint and an ending joint.' return ret_list, message def dfs_joint(self, visited, allPaths, currPath, rightPath, joint, tofind): if joint == tofind: rightPath.append(currPath) elif joint not in visited: visited.append(joint) relatives = mc.listRelatives(joint) if relatives: for j in relatives: newPath = currPath.copy() newPath.append(j) self.dfs_joint(visited, allPaths, newPath, rightPath, j, tofind) else: allPaths.append(currPath) testWindow = BendBowCreatorUI() testWindow.create()