""" License: This collection of code named GS CurveTools is a property of George Sladkovsky (Yehor Sladkovskyi) and can not be copied or distributed without his written permission. GS CurveTools v1.3.1 Studio Copyright 2023, George Sladkovsky (Yehor Sladkovskyi) All Rights Reserved Autodesk Maya is a property of Autodesk, Inc. Social Media and Contact Links: Discord Server: https://discord.gg/f4DH6HQ Online Store: https://sladkovsky3d.artstation.com/store Online Documentation: https://gs-curvetools.readthedocs.io/ Twitch Channel: https://www.twitch.tv/videonomad YouTube Channel: https://www.youtube.com/c/GeorgeSladkovsky ArtStation Portfolio: https://www.artstation.com/sladkovsky3d Contact Email: george.sladkovsky@gmail.com """ import os from functools import partial as pa from imp import reload import maya.cmds as mc import maya.OpenMayaUI as omui from PySide2 import QtCore, QtGui, QtWidgets from shiboken2 import wrapInstance from . import core, uv_editor from .constants import * from .utils import gs_math as mt from .utils import style, tooltips, utils, wrap from .utils.utils import deferred, noUndo, undo from .utils.wrap import WIDGETS reload(core) reload(uv_editor) reload(utils) reload(wrap) reload(style) MESSAGE = utils.logger LOGGER = utils.logger.logger # Maya Main Window and Workspace def mayaMainWindow(): """ Get Maya main window pointer""" mayaWindow = wrapInstance(int(omui.MQtUtil.mainWindow()), QtWidgets.QMainWindow) return mayaWindow def mayaWorkspaceControl(name, label, retain=True, iw=164, ih=783, widthProperty='preferred'): """ Create Maya Dockable Workspace """ try: control = mc.workspaceControl(name, l=label, r=retain, li=True, vis=True, wp=widthProperty, iw=iw, ih=ih, mw=iw, mh=100) except BaseException: LOGGER.debug("Using legacy workspace control") control = mc.workspaceControl(name, l=label, r=retain, li=True, vis=True, wp=widthProperty, iw=iw, ih=ih, mw=iw) qtControl = omui.MQtUtil.findControl(control) dock = wrapInstance(int(qtControl), QtWidgets.QWidget) wrap.WIDGETS[name] = dock return dock def curveControlWorkspace(): if mc.workspaceControl(CURVE_CONTROL_NAME, q=1, ex=1): if MAYA_VER >= 2018: if not mc.workspaceControl(CURVE_CONTROL_NAME, q=1, vis=1): mc.workspaceControl(CURVE_CONTROL_NAME, e=1, rs=1) deferred(core.updateMainUI)() else: mc.workspaceControl(CURVE_CONTROL_NAME, e=1, vis=0) else: mc.workspaceControl(CURVE_CONTROL_NAME, e=1, fl=1) mc.deleteUI(CURVE_CONTROL_NAME) else: CurveControlUI() core.curveControlUI.updateUI() from . import main main.checkScriptJobs(CURVE_CONTROL_NAME) class CurveControlUI(QtWidgets.QWidget): def __init__(self): parent = mayaWorkspaceControl(name=CURVE_CONTROL_NAME, label=CURVE_CONTROL_LABEL, retain=False, iw=350, ih=750, widthProperty="free") # Dockable Workspace Connection super(CurveControlUI, self).__init__(parent) self.ui() parent.layout().addWidget(self) def ui(self): # Layout mainLayout = QtWidgets.QVBoxLayout(self) mainLayout.setContentsMargins(*style.scale([2, 0, 2, 0])) self.scrollWidget = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout(self.scrollWidget) scrollArea = QtWidgets.QScrollArea() scrollArea.setWidget(self.scrollWidget) mainLayout.addWidget(scrollArea) # Layout Settings layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(style.scale(2)) layout.setMargin(0) layout.setAlignment(QtCore.Qt.AlignTop) scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) scrollArea.setWidgetResizable(True) # Main Controls layout.addWidget(wrap.separator()) # Layer Selector, Color Picker, Curve Name and Line Thickness with wrap.Row(layout, 'gsCurveControlHeader') as row: layerSelector = wrap.LayerSelector('gsLayerSelector', row.layout()) layerSelector.setFixedWidth(style.scale(40)) layerSelector.currentIndexChanged.connect(core.changeLayerViaOptionMenu) layerColorPicker = wrap.ColorPicker('gsColorPicker', row.layout()) layerColorPicker.setContentsMargins(*style.scale([3, 3, 1, 3])) layerColorPicker.setFixedWidth(style.scale(20)) layerColorPicker.connectCommand(core.toggleColor.changeLayerColor) curveColorPicker = wrap.ColorPicker('gsCurveColorPicker', row.layout()) curveColorPicker.setContentsMargins(*style.scale([1, 3, 2, 3])) curveColorPicker.setFixedWidth(style.scale(20)) curveColorPicker.connectCommand(core.toggleColor.changeCurveColor) selectedObjectName = wrap.LineEdit('selectedObjectName', row.layout()) selectedObjectName.setPlaceholderText('Select Curve') selectedObjectName.returnPressed.connect(undo(core.renameSelected)) lineThickness = wrap.FloatField('lineWidth', row.layout()) lineThickness.setFixedWidth(style.scale(35)) lineThickness.setRange(-1, 10) lineThickness.setValue(-1) lineThickness.setDragCommand(pa(core.sliders.curveControlSliderDrag, lineThickness)) lineThickness.setReleaseCommand(core.sliders.release) layout.addWidget(wrap.separator()) # Select Curves Prompt label = wrap.Label(layout, 'selectCurvesPrompt') label.setLabel('Select Compatible Curves') label.setFontSize(14) label.setVisible(False) # Axis Control with wrap.Column(layout, 'axisFrame') as column: label = wrap.Label(column.layout()) label.setLabel('Axis Control') label.setFontSize(14) with wrap.Row(column.layout()) as row: WIDGETS['Axis'] = axisButtonGrp = QtWidgets.QButtonGroup() axisAuto = wrap.Button(row.layout(), 'gsBindAxisAuto') axisAuto.setLabel('Auto', lineHeight=100) axisAuto.setCheckable(True) axisAuto.setButtonStyle('small') axisAuto.setChecked(True) axisAuto.clicked.connect(pa(undo(core.applyAxis), 0)) axisX = wrap.Button(row.layout(), 'gsBindAxisX') axisX.setLabel('X', lineHeight=100) axisX.setCheckable(True) axisX.setButtonStyle('small') axisX.clicked.connect(pa(undo(core.applyAxis), 1)) axisY = wrap.Button(row.layout(), 'gsBindAxisY') axisY.setLabel('Y', lineHeight=100) axisY.setCheckable(True) axisY.setButtonStyle('small') axisY.clicked.connect(pa(undo(core.applyAxis), 2)) axisZ = wrap.Button(row.layout(), 'gsBindAxisZ') axisZ.setLabel('Z', lineHeight=100) axisZ.setCheckable(True) axisZ.setButtonStyle('small') axisZ.clicked.connect(pa(undo(core.applyAxis), 3)) axisButtonGrp.addButton(axisAuto, 0) axisButtonGrp.addButton(axisX, 1) axisButtonGrp.addButton(axisY, 2) axisButtonGrp.addButton(axisZ, 3) axisFlip = wrap.Button(row.layout(), 'AxisFlip') axisFlip.setLabel('Flip', lineHeight=100) axisFlip.setCheckable(True) axisFlip.setButtonStyle('small') axisFlip.clicked.connect(pa(undo(core.applyAxis), -1)) column.layout().addWidget(wrap.separator()) # Edit Original Objects with wrap.Row(column.layout(), margins=style.scale([0, 0, 0, 0]), objName='originalCurvesRow') as originalCurvesRow: selectOriginalCurves = wrap.Button(originalCurvesRow.layout(), 'selectOriginalCurves') selectOriginalCurves.setLabel('Select Original Curves', lineHeight=100) selectOriginalCurves.setButtonStyle('small-filled') selectOriginalCurves.clicked.connect(undo(core.curveControlUI.selectOriginalObjects)) editOrigObj = wrap.Button(originalCurvesRow.layout(), 'editOrigObj') editOrigObj.setLabel('Edit Original Objects', lineHeight=100) editOrigObj.setCheckable(True) editOrigObj.setButtonStyle('small') editOrigObj.clicked.connect(undo(core.curveControlUI.editOriginalObjects)) column.layout().addWidget(wrap.separator()) # Length Divisions with wrap.Row(layout, margins=style.scale([0, 0, 3, 0])) as lengthDivisionsRow: lengthDivision = wrap.ControlSlider(objName='lengthDivisions', typ='int') lengthDivision.setLabel('L-Div') lengthDivision.setMinMax(2, 100) lengthDivision.setFieldMinMax(2, 10000) lengthDivision.setValue(2) lengthDivision.setDragCommand(pa(core.sliders.curveControlSliderDrag, lengthDivision)) lengthDivision.setReleaseCommand(core.sliders.release) dynamicDivisionsToggle = wrap.Button(objName='dynamicDivisions') dynamicDivisionsToggle.setLabel('Auto') dynamicDivisionsToggle.setFixedWidth(style.scale(35)) dynamicDivisionsToggle.setButtonStyle('small') dynamicDivisionsToggle.setCheckable(True) dynamicDivisionsToggle.clicked.connect(undo(core.toggleDynamicDivisions)) lengthDivisionsRow.layout().addWidget(lengthDivision, 4) lengthDivisionsRow.layout().addWidget(dynamicDivisionsToggle, 1) # Width Divisions widthDivision = wrap.ControlSlider(layout, 'widthDivisions', 'int') widthDivision.setLabel('W-Div') widthDivision.setMinMax(2, 31) widthDivision.setFieldMinMax(2, 10000) widthDivision.setValue(2) widthDivision.setDragCommand(pa(core.sliders.curveControlSliderDrag, widthDivision)) widthDivision.setReleaseCommand(core.sliders.release) # Orientation orientation = wrap.ControlSlider(layout, 'Orientation', 'float') orientation.setLabel('Orien') orientation.setMinMax(-180, 180) orientation.setFieldMinMax(-36000, 36000) orientation.setPrecision(1) orientation.setStep(0.5) orientation.setDragCommand(pa(core.sliders.curveControlSliderDrag, orientation)) orientation.setReleaseCommand(core.sliders.release) # Twist twist = wrap.ControlSlider(layout, 'Twist', 'float') twist.setLabel('Twist') twist.setMinMax(-180, 180) twist.setFieldMinMax(-36000, 36000) twist.setPrecision(1) twist.setStep(0.5) twist.setDragCommand(pa(core.sliders.curveControlSliderDrag, twist)) twist.setReleaseCommand(core.sliders.release) # Twist invTwist = wrap.ControlSlider(layout, 'invTwist', 'float') invTwist.setLabel('Inv.Twist') invTwist.setMinMax(-180, 180) invTwist.setFieldMinMax(-36000, 36000) invTwist.setPrecision(1) invTwist.setStep(0.5) invTwist.setDragCommand(pa(core.sliders.curveControlSliderDrag, invTwist)) invTwist.setReleaseCommand(core.sliders.release) # Twist Curve Graph with wrap.Frame(layout, 'twistCurveFrame', margins=[0, 1, 0, 2]) as twistCurveFrame: twistCurveFrame.frameButton.setLabel('Twist Curve Graph') twistGraph = wrap.FallOffCurve(twistCurveFrame.getFrameLayout(), 'twistCurve') def twistGraphCommand(_): # BUG: When undoing multiple edits, last edit is not reverted core.attributes.propagateGraphs(twistGraph) core.attributes.storeGraphs(twistGraph) twistGraph.changeCommand(twistGraphCommand) with wrap.Row(twistCurveFrame.getFrameLayout(), margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) magnitude = wrap.FloatField('Magnitude', row.layout()) magnitude.setFixedWidth(style.scale(45)) magnitude.setRange(-99, 99) magnitude.setStep(0.01) magnitude.setPrecision(2) magnitude.setDragCommand(pa(core.sliders.curveControlSliderDrag, magnitude)) magnitude.setReleaseCommand(core.sliders.release) resetButton = wrap.Button(row.layout(), 'gsTwistGraphResetButton') resetButton.setLabel('Reset Curve') def resetTwistCmd(): utils.resetSingleGraph('twist') core.attributes.storeGraphs(twistGraph) resetButton.clicked.connect(undo(resetTwistCmd)) popOutButton = wrap.Button(row.layout(), 'gsTwistGraphPopOut') popOutButton.setFixedWidth(style.scale(56)) popOutButton.setLabel('^') popOutButton.clicked.connect(self.twistGraphPopOut) # Width width = wrap.ControlSlider(layout, 'Width', 'float') width.setLabel('Width') width.setMinMax(0.001, 5) width.setFieldMinMax(0.001, 1000) width.setPrecision(3) width.setStep(0.001) width.setValue(1) width.setDragCommand(pa(core.sliders.curveControlSliderDrag, width)) width.setReleaseCommand(core.sliders.release) # Taper taper = wrap.ControlSlider(layout, 'Taper', 'float') taper.setLabel('Taper') taper.setMinMax(0.001, 3) taper.setFieldMinMax(0.001, 1000) taper.setPrecision(3) taper.setStep(0.001) taper.setValue(1) taper.setDragCommand(pa(core.sliders.curveControlSliderDrag, taper)) taper.setReleaseCommand(core.sliders.release) # Width for Tubes with wrap.Row(layout, objName='widthComboSlider', spacing=0) as row: with wrap.Column(row.layout()) as column: widthX = wrap.ControlSlider(column.layout(), "WidthX", 'float') widthX.setLabel("WidthX") widthX.setMinMax(0.001, 5) widthX.setFieldMinMax(0.001, 1000) widthX.setPrecision(3) widthX.setStep(0.001) widthX.setValue(1) widthX.setDragCommand(pa(core.sliders.curveControlSliderDrag, widthX)) widthX.setReleaseCommand(core.sliders.release) widthZ = wrap.ControlSlider(column.layout(), "WidthZ", 'float') widthZ.setLabel("WidthZ") widthZ.setMinMax(0.001, 5) widthZ.setFieldMinMax(0.001, 1000) widthZ.setPrecision(3) widthZ.setStep(0.001) widthZ.setValue(1) widthZ.setDragCommand(pa(core.sliders.curveControlSliderDrag, widthZ)) widthZ.setReleaseCommand(core.sliders.release) lockButton = wrap.IconCheckButton(row.layout(), 'widthLockSwitch') lockButton.setIcons(utils.getFolder.icons() + 'sliderLock_en_reversed.png', utils.getFolder.icons() + 'sliderLock_reversed.png') lockButton.setIconWidthHeight(10, 30) lockButton.setChecked(True) # Width Curve Graph with wrap.Frame(layout, 'widthCurveFrame', margins=[0, 1, 0, 2]) as widthCurveFrame: widthCurveFrame.frameButton.setLabel('Width Curve Graph') widthGraph = wrap.FallOffCurve(widthCurveFrame.getFrameLayout(), 'scaleCurve') def widthGraphCommand(_): # BUG: When undoing multiple edits, last edit is not reverted core.attributes.propagateGraphs(widthGraph) core.attributes.storeGraphs(widthGraph) widthGraph.changeCommand(widthGraphCommand) with wrap.Row(widthCurveFrame.getFrameLayout(), margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) resetButton = wrap.Button(row.layout(), 'gsWidthGraphResetButton') resetButton.setLabel('Reset Curve') def resetWidthCmd(): utils.resetSingleGraph('scale') core.attributes.storeGraphs(widthGraph) resetButton.clicked.connect(undo(resetWidthCmd)) popOutButton = wrap.Button(row.layout(), 'gsWidthGraphPopOut') popOutButton.setFixedWidth(style.scale(56)) popOutButton.setLabel('^') popOutButton.clicked.connect(self.widthGraphPopOut) # Length Unlock Switch lengthUnlock = wrap.Button(layout, 'LengthLock') lengthUnlock.setLabel('Length Unlock', lineHeight=100) lengthUnlock.setCheckable(True) lengthUnlock.setButtonStyle('small') lengthUnlock.setFixedWidth(style.scale(106)) lengthUnlock.clicked.connect(pa(core.curveControlCheckBoxes, 2)) # Length length = wrap.ControlSlider(layout, 'Length', 'float') length.setLabel('Length') length.setMinMax(0.001, 3) length.setFieldMinMax(-1000, 1000) length.setPrecision(3) length.setStep(0.001) length.setValue(1) length.setDragCommand(pa(core.sliders.curveControlSliderDrag, length)) length.setReleaseCommand(core.sliders.release) # TODO: Offset card from curve attribute # Offset offset = wrap.ControlSlider(layout, 'Offset', 'float') offset.setLabel('Offset') offset.setMinMax(-1, 1) offset.setFieldMinMax(-30, 30) offset.setStep(0.001) offset.setValue(1) offset.setDragCommand(pa(core.sliders.curveControlSliderDrag, offset)) offset.setReleaseCommand(core.sliders.release) # Profile profile = wrap.ControlSlider(layout, 'Profile', 'float') profile.setLabel('Profile') profile.setMinMax(-2, 2) profile.setFieldMinMax(-1000, 1000) profile.setStep(0.001) profile.setDragCommand(pa(core.sliders.curveControlSliderDrag, profile)) profile.setReleaseCommand(core.sliders.release) # Profile Curve Graph with wrap.Frame(layout, 'profileCurveGraph', margins=[0, 1, 0, 2]) as profileCurveFrame: profileCurveFrame.frameButton.setLabel('Profile Curve Graph') profileGraph = wrap.FallOffCurve(profileCurveFrame.getFrameLayout(), 'profileCurve', attr=False) def changeCommand(value): core.updateLattice(value) core.equalizeProfileCurve() core.attributes.storeGraphs(profileGraph) profileGraph.changeCommand(changeCommand) profileSmoothingSlider = wrap.ControlSlider(profileCurveFrame.getFrameLayout(), 'profileSmoothing', 'int') profileSmoothingSlider.setLabel('Smoothing') profileSmoothingSlider.setMinMax(2, 30) profileSmoothingSlider.setValue(2) profileSmoothingSlider.setDragCommand(pa(core.sliders.curveControlSliderDrag, profileSmoothingSlider)) profileSmoothingSlider.setReleaseCommand(core.sliders.release) with wrap.Row(profileCurveFrame.getFrameLayout(), margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) profileMagnitude = wrap.FloatField('profileMagnitude', row.layout()) profileMagnitude.setFixedWidth(style.scale(45)) profileMagnitude.setValue(1) profileMagnitude.setRange(-2, 2) profileMagnitude.setStep(0.01) profileMagnitude.setPrecision(2) profileMagnitude.setDragCommand(pa(core.sliders.curveControlSliderDrag, profileMagnitude)) profileMagnitude.setReleaseCommand(core.sliders.release) with wrap.Column(row.layout(), spacing=0) as eqColumn: eqColumn.setFixedHeight(style.scale(24)) with wrap.Row(eqColumn.layout(), spacing=0) as eqRow: def toggleEq(): WIDGETS['equalizeCurveButton'].setDisabled( WIDGETS['autoEqualizeSwitchOn'].isChecked() ) autoEqualizeGroup = QtWidgets.QButtonGroup(eqRow.layout()) autoEqualizeGroup.buttonClicked.connect(toggleEq) autoEqualizeGroup.buttonClicked.connect(undo(core.equalizeProfileCurve)) autoEqualize = wrap.Button(eqRow.layout(), 'autoEqualizeSwitchOn') autoEqualize.setLabel('Auto', lineHeight=100) autoEqualize.setLabelStyle('small') autoEqualize.setButtonStyle('small-compound-top-left') autoEqualize.setCheckable(True) autoEqualize.setChecked(True) autoEqualizeOff = wrap.Button(eqRow.layout(), 'autoEqualizeSwitchOff') autoEqualizeOff.setLabel('Manual', lineHeight=100) autoEqualizeOff.setLabelStyle('small') autoEqualizeOff.setButtonStyle('small-compound-top-right') autoEqualizeOff.setCheckable(True) autoEqualizeGroup.addButton(autoEqualize) autoEqualizeGroup.addButton(autoEqualizeOff) equalizeProfileCurve = wrap.Button(eqColumn.layout(), 'equalizeCurveButton') equalizeProfileCurve.setLabel('Equalize Curve', lineHeight=100) equalizeProfileCurve.setLabelStyle('small') equalizeProfileCurve.setButtonStyle('small-filled-compound-bottom') equalizeProfileCurve.setDisabled(True) equalizeProfileCurve.clicked.connect(pa(undo(core.equalizeProfileCurve), True)) resetButton = wrap.Button(row.layout(), 'gsResetProfileGraphButton') resetButton.setLabel('Reset Curve') def resetButtonClicked(*_): core.resetProfileCurve() core.attributes.storeGraphs(profileGraph) resetButton.clicked.connect(undo(resetButtonClicked)) popOutButton = wrap.Button(row.layout(), 'gsProfileGraphPopOut') popOutButton.setFixedWidth(style.scale(56)) popOutButton.setLabel('^') popOutButton.clicked.connect(self.profileGraphPopOut) # Normals normals = wrap.ControlSlider(layout, 'surfaceNormals', 'float') normals.setLabel('Normals') normals.setMinMax(0, 180) normals.setPrecision(1) normals.setValue(180) normals.setDragCommand(pa(core.sliders.curveControlSliderDrag, normals)) normals.setReleaseCommand(core.sliders.release) # Reverse Normals Switch reverseNormals = wrap.Button(layout, 'reverseNormals') reverseNormals.setLabel('Reverse Normals', lineHeight=100) reverseNormals.setCheckable(True) reverseNormals.setButtonStyle('small') reverseNormals.setFixedWidth(style.scale(106)) reverseNormals.clicked.connect(pa(core.curveControlCheckBoxes, 0)) with wrap.Frame(layout, 'otherFrame', label='Other', margins=[2, 2, 2, 2]) as refineFrame: samplingAccuracy = wrap.ControlSlider(parent=refineFrame.getFrameLayout(), objName='samplingAccuracy', typ='float') samplingAccuracy.setLabel('SamplAcc') samplingAccuracy.setMinMax(0.001, 2) samplingAccuracy.setStep(0.01) samplingAccuracy.setValue(0.33) samplingAccuracy.setDragCommand(pa(core.sliders.curveControlSliderDrag, samplingAccuracy)) samplingAccuracy.setReleaseCommand(core.sliders.release) # Refine with wrap.Row(refineFrame.getFrameLayout(), margins=style.scale([0, 0, 3, 0])) as curveRefineRow: refine = wrap.ControlSlider(layout, 'curveRefine', 'int') refine.setLabel('Refine') refine.setMinMax(0, 100) refine.setFieldMinMax(0, 10000) refine.setValue(20) refine.setDragCommand(pa(core.sliders.curveControlSliderDrag, refine)) refine.setReleaseCommand(core.sliders.release) autoRefineToggle = wrap.Button(objName='autoRefine') autoRefineToggle.setLabel('Auto') autoRefineToggle.setFixedWidth(style.scale(35)) autoRefineToggle.setButtonStyle('small') autoRefineToggle.setCheckable(True) autoRefineToggle.clicked.connect(undo(core.toggleAutoRefine)) curveRefineRow.layout().addWidget(refine, 4) curveRefineRow.layout().addWidget(autoRefineToggle, 1) # Smooth smooth = wrap.ControlSlider(refineFrame.getFrameLayout(), 'curveSmooth', 'float') smooth.setLabel('Smooth') smooth.setMinMax(0, 10) smooth.setDragCommand(pa(core.sliders.curveControlSliderDrag, smooth)) smooth.setReleaseCommand(core.sliders.release) with wrap.Frame(layout, 'orientToNormalsFrame', label='Orient to Normals', margins=[2, 2, 2, 2]) as orientFrame: orientFrame.setVisible(False) def selectMesh(): sel = mc.filterExpand(mc.ls(sl=1, l=1), sm=12) if not sel: sel = mc.ls(hl=1, o=1, l=1) if not sel: MESSAGE.warningInView('Select compatible mesh.') return self.meshName.setText(sel[0]) with wrap.Row(orientFrame.getFrameLayout()) as row: selectMeshBtn = wrap.Button(row.layout(), "gsOrientToNormalsSelectTarget") selectMeshBtn.setFixedWidth(style.scale(100)) selectMeshBtn.setLabel('Select Target') selectMeshBtn.clicked.connect(selectMesh) self.meshName = wrap.LineEdit('gsOrientMeshName', row.layout()) self.meshName.setPlaceholderText('Select or Type Target Mesh') self.meshName.setClearButtonEnabled(True) orientFrame.getFrameLayout().addWidget(wrap.separator()) with wrap.Row(orientFrame.getFrameLayout()) as row: iterationsSlider = wrap.ControlSlider(row.layout(), 'gsIterationsSlider', 'int') iterationsSlider.setMinMax(1, 100) iterationsSlider.setValue(10) iterationsSlider.setLabel('Iterations') autoRefreshButton = wrap.Button(row.layout(), 'orientRefreshViewport') autoRefreshButton.setButtonStyle('small') autoRefreshButton.setCheckable(True) autoRefreshButton.setChecked(True) autoRefreshButton.setWidthHeight(w=style.scale(50)) autoRefreshButton.setLabel('Refresh VP', lineHeight=100) with wrap.Row(orientFrame.getFrameLayout()) as row: minAngleSlider = wrap.ControlSlider(row.layout(), 'gsMinimumAngle', 'float') minAngleSlider.setMinMax(0.1, 90) minAngleSlider.setValue(1) minAngleSlider.setLabel('Min Angle') orientFrame.getFrameLayout().addWidget(wrap.separator()) with wrap.Row(orientFrame.getFrameLayout()) as row: orient = wrap.Button(row.layout(), 'gsOrientToNormals') orient.setLabel('Orient') orient.clicked.connect(undo(core.orientToFaceNormals)) with wrap.Frame(layout, 'solidifyFrame', label='Solidify Controls', margins=[2, 2, 2, 2]) as solidifyFrame: # Solidify Activate solidify = wrap.Button(solidifyFrame.getFrameLayout(), 'solidify') solidify.setLabel('Solidify', lineHeight=100) solidify.setCheckable(True) solidify.setButtonStyle('small') solidify.setFixedWidth(style.scale(106)) solidify.clicked.connect(pa(core.curveControlCheckBoxes, 1)) # Thickness thickness = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyThickness', 'float') thickness.setLabel('Thickness') thickness.setMinMax(0.001, 5) thickness.setFieldMinMax(-100, 100) thickness.setValue(0.25) thickness.setStep(0.01) thickness.setDragCommand(pa(core.sliders.curveControlSliderDrag, thickness)) thickness.setReleaseCommand(core.sliders.release) # Divisions divisions = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyDivisions', 'int') divisions.setLabel('Divisions') divisions.setMinMax(0, 10) divisions.setFieldMinMax(0, 100) divisions.setDragCommand(pa(core.sliders.curveControlSliderDrag, divisions)) divisions.setReleaseCommand(core.sliders.release) # ScaleX solidifyScaleX = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyScaleX', 'float') solidifyScaleX.setLabel('ScaleX') solidifyScaleX.setMinMax(-10, 10) solidifyScaleX.setFieldMinMax(-100, 100) solidifyScaleX.setDragCommand(pa(core.sliders.curveControlSliderDrag, solidifyScaleX)) solidifyScaleX.setReleaseCommand(core.sliders.release) # ScaleY solidifyScaleY = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyScaleY', 'float') solidifyScaleY.setLabel('ScaleY') solidifyScaleY.setMinMax(-10, 10) solidifyScaleY.setFieldMinMax(-100, 100) solidifyScaleY.setDragCommand(pa(core.sliders.curveControlSliderDrag, solidifyScaleY)) solidifyScaleY.setReleaseCommand(core.sliders.release) # Offset offset = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyOffset', 'float') offset.setLabel('Offset') offset.setMinMax(-10, 10) offset.setFieldMinMax(-100, 100) offset.setDragCommand(pa(core.sliders.curveControlSliderDrag, offset)) offset.setReleaseCommand(core.sliders.release) # Normals solidifyNormals = wrap.ControlSlider(solidifyFrame.getFrameLayout(), 'solidifyNormals', 'float') solidifyNormals.setLabel('SNormals') solidifyNormals.setMinMax(0, 180) solidifyNormals.setPrecision(1) solidifyNormals.setValue(180) solidifyNormals.setDragCommand(pa(core.sliders.curveControlSliderDrag, solidifyNormals)) solidifyNormals.setReleaseCommand(core.sliders.release) with wrap.Frame(layout, 'UVFrame', label='UV Controls', margins=[2, 2, 2, 2]) as UVFrame: flipUV = wrap.Button(UVFrame.getFrameLayout(), 'flipUV') flipUV.setLabel('H-Flip UV', lineHeight=100) flipUV.setCheckable(True) flipUV.setButtonStyle('small') flipUV.setFixedWidth(style.scale(106)) flipUV.clicked.connect(pa(undo(core.curveControlCheckBoxes), 3)) # Move U moveU = wrap.ControlSlider(UVFrame.getFrameLayout(), 'moveU', 'float') moveU.setLabel('MoveU') moveU.setMinMax(-0.5, 0.5) moveU.setStep(0.001) moveU.setFieldMinMax(-100, 100) moveU.setDragCommand(pa(core.sliders.curveControlSliderDrag, moveU)) moveU.setReleaseCommand(core.sliders.release) # Move V moveV = wrap.ControlSlider(UVFrame.getFrameLayout(), 'moveV', 'float') moveV.setLabel('MoveV') moveV.setMinMax(-0.5, 0.5) moveV.setStep(0.001) moveV.setFieldMinMax(-100, 100) moveV.setDragCommand(pa(core.sliders.curveControlSliderDrag, moveV)) moveV.setReleaseCommand(core.sliders.release) # Scale U scaleU = wrap.ControlSlider(UVFrame.getFrameLayout(), 'scaleU', 'float') scaleU.setLabel('ScaleU') scaleU.setMinMax(0.001, 1.999) scaleU.setFieldMinMax(0, 100) scaleU.setStep(0.001) scaleU.setValue(1) scaleU.setDragCommand(pa(core.sliders.curveControlSliderDrag, scaleU)) scaleU.setReleaseCommand(core.sliders.release) # Scale V scaleV = wrap.ControlSlider(UVFrame.getFrameLayout(), 'scaleV', 'float') scaleV.setLabel('ScaleV') scaleV.setMinMax(0.001, 1.999) scaleV.setFieldMinMax(0, 100) scaleV.setStep(0.001) scaleV.setValue(1) scaleV.setDragCommand(pa(core.sliders.curveControlSliderDrag, scaleV)) scaleV.setReleaseCommand(core.sliders.release) # Rotate UV rotateUV = wrap.ControlSlider(UVFrame.getFrameLayout(), 'rotateUV', 'float') rotateUV.setLabel('RotUV') rotateUV.setMinMax(-180, 180) rotateUV.setFieldMinMax(-3600, 3600) rotateUV.setPrecision(2) rotateUV.setDragCommand(pa(core.sliders.curveControlSliderDrag, rotateUV)) rotateUV.setReleaseCommand(core.sliders.release) # Rotate UV Root (Legacy) rotateUVRoot = wrap.ControlSlider(UVFrame.getFrameLayout(), 'rotateRootUV', 'float') rotateUVRoot.setLabel('RotRtUV') rotateUVRoot.setMinMax(-180, 180) rotateUVRoot.setFieldMinMax(-3600, 3600) rotateUVRoot.setPrecision(2) rotateUVRoot.setDragCommand(pa(core.sliders.curveControlSliderDrag, rotateUVRoot)) rotateUVRoot.setReleaseCommand(core.sliders.release) rotateUVRoot.setVisible(False) # Rotate Tip UV (Legacy) rotateUVTip = wrap.ControlSlider(UVFrame.getFrameLayout(), 'rotateTipUV', 'float') rotateUVTip.setLabel('RotTipUV') rotateUVTip.setMinMax(-180, 180) rotateUVTip.setFieldMinMax(-3600, 3600) rotateUVTip.setPrecision(2) rotateUVTip.setDragCommand(pa(core.sliders.curveControlSliderDrag, rotateUVTip)) rotateUVTip.setReleaseCommand(core.sliders.release) rotateUVRoot.setVisible(False) # UV Bug Message if MAYA_VER in [2020, 2022] and not mc.optionVar(q='GSCT_UVBugMessageDismissed'): with wrap.Row(UVFrame.getFrameLayout()) as row: label = wrap.Label(row.layout()) label.setLabel('
How To Fix Maya 2020-2022 UV Bug:
') linkButton = wrap.Button(row.layout()) linkButton.setLabel('Open Fix') linkButton.setButtonStyle('small-filled') linkButton.clicked.connect(lambda: utils.openLink( 'https://gs-curvetools.readthedocs.io/en/latest/faq.html#maya-2020-2022-and-broken-uvs')) dismissMessage = wrap.Button(row.layout()) dismissMessage.setLabel('Dismiss') dismissMessage.setButtonStyle('small-filled') dismissMessage.clicked.connect(lambda: row.setHidden(True)) dismissMessage.clicked.connect(lambda: mc.optionVar(iv=['GSCT_UVBugMessageDismissed', 1])) # Advanced Visibility Frame with wrap.Frame(layout, 'advancedVisibilityFrame', label='Advanced Visibility', margins=style.scale([3, 2, 3, 2]), spacing=style.scale(3)) as visibilityFrame: with wrap.Row(visibilityFrame.getFrameLayout()) as row: geometryHighlight = wrap.Button(row.layout(), 'geometryHighlight') geometryHighlight.setLabel('Geometry Highlight', lineHeight=100) geometryHighlight.setCheckable(True) geometryHighlight.setChecked(bool(mc.optionVar(q="GSCT_GeometryHighlightEnabled"))) geometryHighlight.setButtonStyle('small') geometryHighlight.clicked.connect(noUndo(core.advancedVisibility.geometryHighlightCommand)) curveHighlight = wrap.Button(row.layout(), 'curveHighlight') curveHighlight.setLabel('Curve Highlight', lineHeight=100) curveHighlight.setCheckable(True) curveHighlight.setButtonStyle('small') curveHighlight.setChecked(False) curveHighlight.clicked.connect(undo(core.advancedVisibility.toggleCurveHighlightFromUI)) visibilityFrame.getFrameLayout().addWidget(wrap.separator()) def sliderChangeCommand(*_): core.advancedVisibility.applySettingsToNode() core.advancedVisibility.saveSettingsFromUI() with wrap.Column(visibilityFrame.getFrameLayout(), objName='gsCurveHighlightFrame', spacing=style.scale(4)) as column: column.setEnabled(False) # Disable immediately. We are going to check its state later. # CV Size with wrap.Row(column.layout(), spacing=4) as row: CVsizeLabel = wrap.Label() CVsizeLabel.setLabel("CV Size:") CVsizeLabel.setFixedWidth(style.scale(100)) CVsizeLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) pointSizeSlider = wrap.mayaSlider( mc.floatSliderGrp( 'gsPointSizeSlider', f=1, adj=2, w=1, cw=[1, 45], min=1, max=100, v=10, dc=lambda _: noUndo(core.advancedVisibility.applySettingsToNode)(), cc=noUndo(sliderChangeCommand), ) ) WIDGETS['gsPointSizeSlider'] = pointSizeSlider row.layout().addWidget(CVsizeLabel, 0) row.layout().addWidget(pointSizeSlider, 1) # Selected Color with wrap.Row(column.layout(), spacing=style.scale(4)) as row: selectedColorLabel = wrap.Label() selectedColorLabel.setLabel("Selected Color:") selectedColorLabel.setFixedWidth(style.scale(100)) selectedColorLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) selectedColorPicker = wrap.ColorPicker("gsSelectedCVColor") selectedColorPicker.connectDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) selectedColorPicker.connectCommand(noUndo(sliderChangeCommand)) selectedAlphaValue = wrap.FloatField("gsSelectedCVAlpha") selectedAlphaValue.setFixedWidth(style.scale(45)) selectedAlphaValue.setValue(1.0) selectedAlphaValue.setRange(0, 1) selectedAlphaValue.setStep(0.01) selectedAlphaValue.setPrecision(2) selectedAlphaValue.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) selectedAlphaValue.setReleaseCommand(noUndo(sliderChangeCommand)) row.layout().addWidget(selectedColorLabel, 0) row.layout().addWidget(selectedColorPicker, 1) row.layout().addWidget(selectedAlphaValue, 0) # Deselected Color with wrap.Row(column.layout(), spacing=style.scale(4)) as row: deselectedColorLabel = wrap.Label() deselectedColorLabel.setLabel("Deselected Color:") deselectedColorLabel.setFixedWidth(style.scale(100)) deselectedColorLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) deselectedColorPicker = wrap.ColorPicker("gsDeselectedCVColor") deselectedColorPicker.connectDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) deselectedColorPicker.connectCommand(noUndo(sliderChangeCommand)) deselectedAlphaValue = wrap.FloatField("gsDeselectedCVAlpha") deselectedAlphaValue.setFixedWidth(style.scale(45)) deselectedAlphaValue.setValue(1) deselectedAlphaValue.setRange(0, 1) deselectedAlphaValue.setStep(0.01) deselectedAlphaValue.setPrecision(2) deselectedAlphaValue.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) deselectedAlphaValue.setReleaseCommand(noUndo(sliderChangeCommand)) row.layout().addWidget(deselectedColorLabel, 0) row.layout().addWidget(deselectedColorPicker, 1) row.layout().addWidget(deselectedAlphaValue, 1) column.layout().addWidget(wrap.separator()) # Curve Visibility curveVisibility = wrap.Button(column.layout(), 'curveVisibility') curveVisibility.setLabel('Curve Visibility', lineHeight=100) curveVisibility.setCheckable(True) curveVisibility.setButtonStyle('small') curveVisibility.setChecked(True) curveVisibility.clicked.connect(noUndo(sliderChangeCommand)) with wrap.Row(column.layout(), spacing=4) as row: curveWidthLabel = wrap.Label() curveWidthLabel.setLabel("Curve Width:") curveWidthLabel.setFixedWidth(style.scale(100)) curveWidthLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) curveWidthSlider = wrap.mayaSlider( mc.floatSliderGrp( 'gsCurveWidthSlider', f=1, adj=2, w=1, cw=[1, 45], min=1, max=100, v=4, dc=lambda _: noUndo(core.advancedVisibility.applySettingsToNode)(), cc=noUndo(sliderChangeCommand), ), ) WIDGETS['gsCurveWidthSlider'] = curveWidthSlider row.layout().addWidget(curveWidthLabel, 0) row.layout().addWidget(curveWidthSlider, 1) with wrap.Row(column.layout(), spacing=style.scale(4)) as row: curveHighlightColorLabel = wrap.Label() curveHighlightColorLabel.setLabel("Curve Color:") curveHighlightColorLabel.setFixedWidth(style.scale(100)) curveHighlightColorLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) curveHighlightColor = wrap.ColorPicker("gsCurveHighlightColor") curveHighlightColor.connectDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) curveHighlightColor.connectCommand(noUndo(sliderChangeCommand)) curveHighlightAlpha = wrap.FloatField("gsCurveHighlightAlpha") curveHighlightAlpha.setFixedWidth(style.scale(45)) curveHighlightAlpha.setValue(1.0) curveHighlightAlpha.setRange(0, 1) curveHighlightAlpha.setStep(0.01) curveHighlightAlpha.setPrecision(2) curveHighlightAlpha.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) curveHighlightAlpha.setReleaseCommand(noUndo(sliderChangeCommand)) row.layout().addWidget(curveHighlightColorLabel, 0) row.layout().addWidget(curveHighlightColor, 1) row.layout().addWidget(curveHighlightAlpha, 1) column.layout().addWidget(wrap.separator()) # Hull Visibility hullVisibility = wrap.Button(column.layout(), 'hullVisibility') hullVisibility.setLabel('Hull Visibility', lineHeight=100) hullVisibility.setCheckable(True) hullVisibility.setButtonStyle('small') hullVisibility.clicked.connect(noUndo(sliderChangeCommand)) with wrap.Row(column.layout(), spacing=4) as row: hullWidthLabel = wrap.Label() hullWidthLabel.setLabel("Hull Width:") hullWidthLabel.setFixedWidth(style.scale(100)) hullWidthLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) hullWidthSlider = wrap.mayaSlider( mc.floatSliderGrp( 'gsHullWidthSlider', f=1, adj=2, w=1, cw=[1, 45], min=1, max=100, v=3, dc=lambda _: noUndo(core.advancedVisibility.applySettingsToNode)(), cc=noUndo(sliderChangeCommand), ) ) WIDGETS['gsHullWidthSlider'] = hullWidthSlider row.layout().addWidget(hullWidthLabel, 0) row.layout().addWidget(hullWidthSlider, 1) with wrap.Row(column.layout(), spacing=style.scale(4)) as row: hullColorLabel = wrap.Label() hullColorLabel.setLabel("Hull Color:") hullColorLabel.setFixedWidth(style.scale(100)) hullColorLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) hullColor = wrap.ColorPicker("gsHullHighlightColor") hullColor.connectDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) hullColor.connectCommand(noUndo(sliderChangeCommand)) hullAlpha = wrap.FloatField("gsHullHighlightAlpha") hullAlpha.setFixedWidth(style.scale(45)) hullAlpha.setValue(1.0) hullAlpha.setRange(0, 1) hullAlpha.setStep(0.01) hullAlpha.setPrecision(2) hullAlpha.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) hullAlpha.setReleaseCommand(noUndo(sliderChangeCommand)) row.layout().addWidget(hullColorLabel, 0) row.layout().addWidget(hullColor, 1) row.layout().addWidget(hullAlpha, 1) column.layout().addWidget(wrap.separator()) with wrap.Frame(column.layout(), 'advancedVisibilityFrame', label='Other Options:', margins=style.scale([3, 2, 3, 2]), spacing=style.scale(3)) as optionsFrame: with wrap.Row(optionsFrame.getFrameLayout()) as row: lazyUpdate = wrap.Button(row.layout(), 'lazyUpdate') lazyUpdate.setLabel("Lazy Update", lineHeight=100) lazyUpdate.setCheckable(True) lazyUpdate.setButtonStyle('small') lazyUpdate.clicked.connect(noUndo(sliderChangeCommand)) alwaysOnTop = wrap.Button(row.layout(), 'alwaysOnTop') alwaysOnTop.setLabel("Always On Top", lineHeight=100) alwaysOnTop.setCheckable(True) alwaysOnTop.setButtonStyle('small') alwaysOnTop.setChecked(True) alwaysOnTop.clicked.connect(noUndo(sliderChangeCommand)) optionsFrame.getFrameLayout().addWidget(wrap.separator()) experimentalLabel = wrap.Label(optionsFrame.getFrameLayout()) experimentalLabel.setLabel("Distance Colors:") with wrap.Row(optionsFrame.getFrameLayout()) as row: curveDistanceColor = wrap.Button(row.layout(), 'curveDistanceColor') curveDistanceColor.setLabel("Curve", lineHeight=100) curveDistanceColor.setCheckable(True) curveDistanceColor.setButtonStyle('small') curveDistanceColor.setChecked(True) curveDistanceColor.clicked.connect(noUndo(sliderChangeCommand)) cvDistanceColor = wrap.Button(row.layout(), 'cvDistanceColor') cvDistanceColor.setLabel("CV", lineHeight=100) cvDistanceColor.setCheckable(True) cvDistanceColor.setButtonStyle('small') cvDistanceColor.setChecked(True) cvDistanceColor.clicked.connect(noUndo(sliderChangeCommand)) hullDistanceColor = wrap.Button(row.layout(), 'hullDistanceColor') hullDistanceColor.setLabel("Hull", lineHeight=100) hullDistanceColor.setCheckable(True) hullDistanceColor.setButtonStyle('small') hullDistanceColor.setChecked(True) hullDistanceColor.clicked.connect(noUndo(sliderChangeCommand)) with wrap.Row(optionsFrame.getFrameLayout()) as row: distanceColorMinLabel = wrap.Label() distanceColorMinLabel.setLabel("Color Min:") distanceColorMinLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) distanceColorMinInput = wrap.FloatField("gsDistanceColorMinValue") distanceColorMinInput.setValue(0.25) distanceColorMinInput.setRange(0.01, 1) distanceColorMinInput.setStep(0.01) distanceColorMinInput.setPrecision(2) distanceColorMinInput.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) distanceColorMinInput.setReleaseCommand(noUndo(sliderChangeCommand)) distanceColorMaxLabel = wrap.Label() distanceColorMaxLabel.setLabel("Color Max:") distanceColorMaxLabel.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) distanceColorMaxInput = wrap.FloatField("gsDistanceColorMaxValue") distanceColorMaxInput.setValue(1.0) distanceColorMaxInput.setRange(0.01, 1) distanceColorMaxInput.setStep(0.01) distanceColorMaxInput.setPrecision(2) distanceColorMaxInput.setDragCommand(lambda *_: noUndo(core.advancedVisibility.applySettingsToNode)()) distanceColorMaxInput.setReleaseCommand(noUndo(sliderChangeCommand)) row.layout().addWidget(distanceColorMinLabel, 1) row.layout().addWidget(distanceColorMinInput, 1) row.layout().addWidget(distanceColorMaxLabel, 1) row.layout().addWidget(distanceColorMaxInput, 1) optionsFrame.getFrameLayout().addWidget(wrap.separator()) experimentalLabel = wrap.Label(optionsFrame.getFrameLayout()) experimentalLabel.setLabel("Experimental (possibly slow):") CVocclusion = wrap.Button(optionsFrame.getFrameLayout(), 'CVocclusion') CVocclusion.setLabel("Enable CV Occlusion", lineHeight=100) CVocclusion.setCheckable(True) CVocclusion.setButtonStyle('small') CVocclusion.clicked.connect(noUndo(sliderChangeCommand)) with wrap.Row(optionsFrame.getFrameLayout(), spacing=style.scale(4)) as row: selectOccluderButton = wrap.Button(row.layout(), "gsSelectOccluderButton") selectOccluderButton.setFixedWidth(style.scale(100)) selectOccluderButton.setLabel('Select Occluder') selectOccluderButton.clicked.connect(noUndo(core.advancedVisibility.selectOccluderFromScene)) occluderMeshName = wrap.LineEdit('gsOccluderMeshName', row.layout()) occluderMeshName.setPlaceholderText('Select or Type Occluder Mesh Name') occluderMeshName.setClearButtonEnabled(True) occluderMeshName.editingFinished.connect(noUndo(sliderChangeCommand)) core.advancedVisibility.loadSettingsFromOptionVar() tooltips.toggleCustomTooltipsCurveControl(core.getOption('enableTooltips')) layout.addWidget(wrap.separator()) resetButton = wrap.Button(layout, 'resetControlSliders') resetButton.setLabel('Reset Sliders Range') resetButton.clicked.connect(core.resetControlSliders) def twistGraphPopOut(self): name = "GSCT_TwistGraphPopOut" if mc.workspaceControl(name, q=1, ex=1): mc.deleteUI(name) popOut = CreatePopOut(name, "Twist Graph Large", 512, 400) graph = wrap.FallOffCurve(popOut.widgetLayout, 'twistCurve_large') def twistGraphCommand(_): core.attributes.propagateGraphs(graph) core.attributes.storeGraphs(graph) graph.changeCommand(twistGraphCommand) with wrap.Row(popOut.widgetLayout, margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) magnitude = wrap.FloatField('Magnitude_large', row.layout(), attrName='Magnitude') magnitude.setFixedWidth(style.scale(45)) magnitude.setRange(-99, 99) magnitude.setStep(0.01) magnitude.setPrecision(2) magnitude.setDragCommand(pa(core.sliders.curveControlSliderDrag, magnitude)) magnitude.setReleaseCommand(core.sliders.release) resetButton = wrap.Button(row.layout()) resetButton.setLabel('Reset Curve') def resetTwist(): utils.resetSingleGraph('twist') core.attributes.storeGraphs(graph) resetButton.clicked.connect(undo(resetTwist)) core.curveControlUI.updateUI() def widthGraphPopOut(self): name = "GSCT_WidthGraphPopOut" if mc.workspaceControl(name, q=1, ex=1): mc.deleteUI(name) popOut = CreatePopOut(name, "Width Graph Large", 512, 400) graph = wrap.FallOffCurve(popOut.widgetLayout, 'scaleCurve_large') def widthGraphCommand(_): core.attributes.propagateGraphs(graph) core.attributes.storeGraphs(graph) graph.changeCommand(widthGraphCommand) with wrap.Row(popOut.widgetLayout, margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) resetButton = wrap.Button(row.layout()) resetButton.setLabel('Reset Curve') def resetWidthCmd(): utils.resetSingleGraph('width') core.attributes.storeGraphs(graph) resetButton.clicked.connect(undo(resetWidthCmd)) core.curveControlUI.updateUI() def profileGraphPopOut(self): name = "GSCT_ProfileGraphPopOut" if mc.workspaceControl(name, q=1, ex=1): mc.deleteUI(name) popOut = CreatePopOut(name, "Profile Graph Large", 512, 400) graph = wrap.FallOffCurve(popOut.widgetLayout, 'profileCurve_large', attr=False) def changeCommand(value): core.updateLattice(value) core.equalizeProfileCurve() graph.changeCommand(changeCommand) with wrap.Row(popOut.widgetLayout, margins=style.scale([5, 0, 5, 2])) as row: row.setFixedHeight(style.BUTTON_HEIGHT) resetButton = wrap.Button(row.layout()) resetButton.setLabel('Reset Curve') resetButton.clicked.connect(undo(core.resetProfileCurve)) core.curveControlUI.updateUI() # UV Editor Window def uvEditorWorkspace(): global uveditor if mc.workspaceControl(UV_EDITOR_NAME, q=1, ex=1): if MAYA_VER >= 2018: if not mc.workspaceControl(UV_EDITOR_NAME, q=1, vis=1): mc.workspaceControl(UV_EDITOR_NAME, e=1, rs=1) else: mc.workspaceControl(UV_EDITOR_NAME, e=1, vis=0) try: uveditor.updateEditor() # pylint: disable=used-before-assignment except Exception as e: LOGGER.exception(e) else: mc.workspaceControl(UV_EDITOR_NAME, e=1, fl=1) mc.deleteUI(UV_EDITOR_NAME) else: uveditor = UVEditor('uveditor') uveditor.init() uveditor.updateEditor() from . import main main.checkScriptJobs(UV_EDITOR_NAME) class UVEditor(QtWidgets.QWidget): def __init__(self, name): super(UVEditor, self).__init__() self.name = name self.timer = utils.Timer() self.mouseToggle = False self.previousSelection = [] self.uvUpdateCheck = 0 self.isolateMode = False self.currentSelection = [] def init(self): if mc.workspaceControl(UV_EDITOR_NAME, q=1, ex=1): mc.deleteUI(UV_EDITOR_NAME) parent = mayaWorkspaceControl(name=UV_EDITOR_NAME, label=UV_EDITOR_LABEL, retain=False, iw=705, ih=575, widthProperty="free") self.setParent(parent) parent.layout().addWidget(self) self.window() self.editor.signal_keyPress.connect(self.updateButtons) self.editor.signal_mouseMove.connect(self._updateCurves) self.editor.signal_mouseRelease.connect(self._stopCurvesUpdate) self.editor.signal_uvDrawEnd.connect(self.manualCurveUpdate) self.editor.signal_functionKeyPress.connect(undo(self.functionSwitch)) self.uvList.signal_keyPressed.connect(self.updateVisibility) def window(self): # Layout mainLayout = QtWidgets.QVBoxLayout(self) mainLayout.setContentsMargins(*style.scale([2, 2, 2, 2])) self.scrollWidget = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout(self.scrollWidget) scrollArea = QtWidgets.QScrollArea() scrollArea.setWidget(self.scrollWidget) mainLayout.addWidget(scrollArea) # Layout Settings layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(style.scale(2)) layout.setMargin(0) layout.setAlignment(QtCore.Qt.AlignTop) scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) scrollArea.setWidgetResizable(True) # Editor Init self.editor = uv_editor.Editor() self.editor.init() self.updateColors() # Main Widgets with wrap.Row(layout) as mainRow: with wrap.Column(mainRow.layout()) as mainColumn: mainColumn.layout().setAlignment(QtCore.Qt.AlignTop) mainColumn.setFixedWidth(style.scale(130)) # Controller switches mainColumn.layout().addWidget(wrap.separator()) controllerLabel = wrap.Label(mainColumn.layout()) controllerLabel.setLabel('Controller Mode') self.controllerGroup = QtWidgets.QButtonGroup(mainColumn.layout()) self.controllerGroup.buttonReleased.connect(self.updateControllerMode) with wrap.Row(mainColumn.layout()) as selectMove: select = wrap.Button(selectMove.layout(), 'gsUVSelect') select.setCheckable(True) select.setChecked(True) select.setLabel("Select (Q)") move = wrap.Button(selectMove.layout(), 'gsUVMove') move.setCheckable(True) move.setLabel("Move (W)") with wrap.Row(mainColumn.layout()) as rotateScale: rotate = wrap.Button(rotateScale.layout(), 'gsUVRotate') rotate.setCheckable(True) rotate.setLabel("Rotate (E)") scale = wrap.Button(rotateScale.layout(), 'gsUVScale') scale.setCheckable(True) scale.setLabel("Scale (R)") with wrap.Row(mainColumn.layout()) as scaleRow: self.directionSwitch = QtWidgets.QButtonGroup(scaleRow.layout()) self.directionSwitch.buttonReleased.connect(self.updateControllerMode) horizontal = wrap.Button(scaleRow.layout(), 'gsUVHorizontalScale') horizontal.setLabel('H') horizontal.setButtonStyle('small') horizontal.setCheckable(True) horizontal.setChecked(True) vertical = wrap.Button(scaleRow.layout(), 'gsUVVerticalScale') vertical.setButtonStyle('small') vertical.setCheckable(True) vertical.setLabel('V') self.directionSwitch.addButton(horizontal, 0) self.directionSwitch.addButton(vertical, 1) drawUV = wrap.Button(mainColumn.layout(), 'gsDrawUVs') drawUV.setCheckable(True) drawUV.setLabel('Draw (D)') self.controllerGroup.addButton(select, 0) self.controllerGroup.addButton(move, 1) self.controllerGroup.addButton(rotate, 2) self.controllerGroup.addButton(scale, 3) self.controllerGroup.addButton(drawUV, 4) mainColumn.layout().addWidget(wrap.separator()) # Utility Functions utilityLabel = wrap.Label(mainColumn.layout()) utilityLabel.setLabel('Utility Functions') with wrap.Row(mainColumn.layout()) as HVFlip: hFlipUV = wrap.Button(HVFlip.layout(), 'gsHorizontalFlipUV') hFlipUV.setLabel('H-Flip (H)') hFlipUV.clicked.connect(undo(self.horizontalFlipUV)) vFlipUV = wrap.Button(HVFlip.layout(), 'gsVerticalFlipUV') vFlipUV.setLabel('V-Flip (V)') vFlipUV.clicked.connect(undo(self.verticalFlipUV)) resetUV = wrap.Button(mainColumn.layout(), 'gsResetUVs') resetUV.setLabel('Reset UV (X)') resetUV.clicked.connect(undo(self.resetUVs)) syncSelection = wrap.Button(mainColumn.layout(), 'gsSyncSelectionUVs') syncSelection.setLabel('Sync Selection (S)') syncSelection.clicked.connect(undo(self.syncSelection)) randomizeUVs = wrap.Button(mainColumn.layout(), 'gsRandomizeUVs') randomizeUVs.setLabel('Randomize') randomizeUVs.setIcon('mod-bottom') randomizeUVs.clicked.connect(undo(self.randomizeUVs)) mainColumn.layout().addWidget(wrap.separator()) # UV List uvListLabel = wrap.Label(mainColumn.layout()) uvListLabel.setLabel('UV List') self.uvList = wrap.UVItemList(mainColumn.layout()) self.uvList.setLayout(mainColumn.layout()) self.uvList.signal_mouseReleased.connect(self.updateVisibility) focusView = wrap.Button(mainColumn.layout(), 'gsFocusUVs') focusView.setLabel('Focus View (F)') focusView.clicked.connect(self.editor.focusView) with wrap.Row(mainColumn.layout()) as hideIsolate: isolateSelect = wrap.Button(hideIsolate.layout(), 'gsUVIsolateSelect') isolateSelect.setLabel('Isolate (I)') isolateSelect.clicked.connect(self.isolateSelect) hide = wrap.Button(hideIsolate.layout(), 'gsUVHide') hide.setLabel('Hide (O)') hide.clicked.connect(self.hide) showAllButton = wrap.Button(mainColumn.layout(), 'gsUVShowAll') showAllButton.setLabel('Show All (A)') showAllButton.clicked.connect(self.showAll) mainColumn.layout().addWidget(wrap.separator()) with wrap.Frame(mainColumn.layout(), label="Options") as optionsFrame: # Texture Controls textureFunctionsLabel = wrap.Label(optionsFrame.getFrameLayout()) textureFunctionsLabel.setLabel('Texture Controls:') transparency = wrap.Button(optionsFrame.getFrameLayout(), 'UVEditorTransparencyToggle') transparency.setButtonStyle('small') transparency.setCheckable(True) transparency.setChecked(mc.optionVar(q='GSCT_UVEditorTransparencyToggle')) transparency.setLabel("Transparency") alphaOnly = wrap.Button(optionsFrame.getFrameLayout(), 'UVEditorAlphaOnlyToggle') alphaOnly.setButtonStyle('small') alphaOnly.setCheckable(True) alphaOnly.setChecked(mc.optionVar(q='GSCT_UVEditorAlphaOnly')) alphaOnly.setLabel("Alpha Only") useTransforms = wrap.Button(optionsFrame.getFrameLayout(), 'UVEditorUseTransforms') useTransforms.setButtonStyle('small') useTransforms.setCheckable(True) useTransforms.setChecked(True) useTransforms.setLabel("Use Transforms") useTransforms.clicked.connect(self.updateTexture) def toggleAlphaCommand(): if transparency.isChecked(): self.editor.toggleAlpha(True) else: self.editor.toggleAlpha(False) alphaOnly.setChecked(False) self.updateTexture() mc.optionVar(iv=['GSCT_UVEditorTransparencyToggle', transparency.isChecked()]) transparency.clicked.connect(toggleAlphaCommand) def toggleAlphaOnlyCommand(): # BUG: Find out why switching textures does not update alpha if alphaOnly.isChecked(): transparency.setChecked(True) else: transparency.setChecked(False) toggleAlphaCommand() mc.optionVar(iv=['GSCT_UVEditorAlphaOnly', alphaOnly.isChecked()]) alphaOnly.clicked.connect(toggleAlphaOnlyCommand) optionsFrame.getFrameLayout().addWidget(wrap.separator()) # Editor Colors textureFunctionsLabel = wrap.Label(optionsFrame.getFrameLayout()) textureFunctionsLabel.setLabel('Editor Colors:') with wrap.Row(optionsFrame.getFrameLayout(), margins=style.scale([5, 0, 5, 5])) as colorRow: backgroundColorPicker = wrap.ColorPicker('UVEditorBGColorPicker', colorRow.layout()) backgroundColorPicker.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorBGColor"))) ) backgroundColorPicker.connectCommand(self.updateColors) gridColorPicker = wrap.ColorPicker('UVEditorGridColorPicker', colorRow.layout()) gridColorPicker.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorGridColor"))) ) gridColorPicker.connectCommand(self.updateColors) frameColorPicker = wrap.ColorPicker('UVEditorFrameColorPicker', colorRow.layout()) frameColorPicker.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorFrameColor"))) ) frameColorPicker.connectCommand(self.updateColors) # UV Card Colors cardColors = wrap.Label(optionsFrame.getFrameLayout()) cardColors.setLabel('UV Colors:') with wrap.Row(optionsFrame.getFrameLayout(), margins=style.scale([5, 0, 5, 5])) as colorRow2: selectedCardFrameColor = wrap.ColorPicker('UVEditorUVFrameSelectedColorPicker', colorRow2.layout()) selectedCardFrameColor.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorUVFrameSelectedColor"))) ) selectedCardFrameColor.connectCommand(self.updateColors) deselectedCardFrameColor = wrap.ColorPicker('UVEditorUVFrameDeselectedColorPicker', colorRow2.layout()) deselectedCardFrameColor.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorUVFrameDeselectedColor"))) ) deselectedCardFrameColor.connectCommand(self.updateColors) cardFillColor = wrap.ColorPicker('UVEditorUVCardFillColorPicker', colorRow2.layout()) cardFillColor.setRGBColors( utils.colorFrom255to1(eval(mc.optionVar(q="GSCT_UVEditorUVCardFillColor"))) ) cardFillColor.connectCommand(self.updateColors) mainColumn.layout().addWidget(wrap.separator()) mainRow.layout().addWidget(self.editor) if MAYA_VER in [2020, 2022] and not mc.optionVar(q='GSCT_UVBugMessageDismissed'): with wrap.Row(mainLayout) as row: label = wrap.Label(row.layout()) label.setLabel('How To Fix Maya 2020-2022 UV Bug:
') linkButton = wrap.Button(row.layout()) linkButton.setLabel('Open Fix') linkButton.setButtonStyle('small-filled') linkButton.clicked.connect(lambda: utils.openLink( 'https://gs-curvetools.readthedocs.io/en/latest/faq.html#maya-2020-2022-and-broken-uvs') ) dismissMessage = wrap.Button(row.layout()) dismissMessage.setLabel('Dismiss Message') dismissMessage.setButtonStyle('small-filled') dismissMessage.clicked.connect(lambda: row.setHidden(True)) dismissMessage.clicked.connect(lambda: mc.optionVar(iv=['GSCT_UVBugMessageDismissed', 1])) def updateColors(self, *_): if self.editor: core.saveOptions() try: self.editor.changeColor( eval(mc.optionVar(q="GSCT_UVEditorBGColor")), eval(mc.optionVar(q="GSCT_UVEditorGridColor")), eval(mc.optionVar(q="GSCT_UVEditorFrameColor")), eval(mc.optionVar(q="GSCT_UVEditorUVCardFillColor")), eval(mc.optionVar(q="GSCT_UVEditorUVFrameSelectedColor")), eval(mc.optionVar(q="GSCT_UVEditorUVFrameDeselectedColor")) ) except Exception as e: self.editor.changeColor() LOGGER.exception(e) self.editor.update() @noUndo def updateEditor(self): uveditor.updateItemList() uveditor.updateUVs() uveditor.updateTexture() def showAll(self): self.uvList.expandAll() self.uvList.selectAll() self.updateVisibility() self.isolateMode = False @noUndo def updateUVs(self, keepSelection=False): sel = mc.filterExpand(mc.ls(sl=1, fl=1, l=1), sm=9) oldUVs = self.editor.UVDict self.editor.purgeUVs() if not sel: return sel = self.checkForLegacyUVs(sel) for item in sel: if (mc.attributeQuery('Orientation', n=item, ex=1) and mc.connectionInfo(item + '.Orientation', isSource=1)): if (mc.attributeQuery('gsmessage', n=item, ex=1) and mc.listConnections(item + '.gsmessage')): curves = core.getAllConnectedCurves(item) else: curves = [item] for curve in curves: attrs = core.attributes.getUVs(curve) cb = core.attributes.getCheckboxes(curve) if attrs: uv = self.editor.createUV(curve) if 'flipUV' in cb: uv.flip = not cb['flipUV'] uv.moveUV( x=attrs['moveU'], y=attrs['moveV'], rot=attrs['rotateUV'] * -1, sx=attrs['scaleU'], sy=attrs['scaleV'], ) if keepSelection: newUVs = self.editor.UVDict for uv in newUVs: if uv in oldUVs: newUVs[uv].setSelected(True) def checkForLegacyUVs(self, curves): legacyCurves = [] for curve in curves: root = mc.attributeQuery('rotateRootUV', n=curve, ex=1) tip = mc.attributeQuery('rotateTipUV', n=curve, ex=1) if root or tip: rootValue = mc.getAttr(curve + '.rotateRootUV') tipValue = mc.getAttr(curve + '.rotateTipUV') if rootValue or tipValue: legacyCurves.append(curve) if not legacyCurves: return curves else: MESSAGE.warningInView('Non Zero Legacy UV Attributes Detected') dialog = mc.confirmDialog( title='Legacy UVs', message='Non Zero Legacy UVs Detected.\nUV Editor is not compatible with them.\nZero them out to proceed?', icon='warning', button=['Yes', 'Cancel'], cancelButton='Cancel', dismissString='Cancel' ) if dialog == 'Yes': for curve in legacyCurves: mc.setAttr(curve + '.rotateRootUV', 0) mc.setAttr(curve + '.rotateTipUV', 0) return curves elif dialog == 'Cancel': dialog = mc.confirmDialog( title='Legacy UVs', message='UV Editor is not compatible with the old UVs.\nSome of the cards are ignored.', icon='information', button='OK', cancelButton='OK', dismissString='OK' ) return list(set(curves) - set(legacyCurves)) @noUndo def updateTexture(self): sel = core.selectPart(2, justReturn=True) if not sel: self.editor.removeTexture() self.editor.diffusePath = '' return geo = mc.filterExpand(sel, sm=12) if not geo: return dag = mc.ls(geo[-1], dag=1, s=1) shader = mc.listConnections(dag, d=1, s=1, t='shadingEngine') if not shader: return network = mc.hyperShade(lun=shader[0]) fileNode = None alphaNode = None if network: for node in network: if mc.nodeType(node) == 'file' and mc.connectionInfo(node + '.outColor', isSource=1): fileNode = node break for node in network: if mc.nodeType(node) == 'file' and mc.connectionInfo(node + '.outTransparency', isSource=1): alphaNode = node break if not fileNode: return texturePath = mc.getAttr(fileNode + '.fileTextureName') alphaPath = mc.getAttr(alphaNode + '.fileTextureName') if alphaNode else None # Find place2dTexture node place2dTexture = None if mc.attributeQuery('coverage', n=fileNode, ex=1): info = mc.connectionInfo(fileNode + '.coverage', sfd=1) if info: place2dTexture = info.split('.') if place2dTexture: place2dTexture = place2dTexture[0] # Get coverage and transformFrame from place2dTexture cov, trans = None, None if place2dTexture and mc.objExists(place2dTexture) and WIDGETS['UVEditorUseTransforms'].isChecked(): if (mc.attributeQuery('coverage', ex=1, n=place2dTexture) and mc.attributeQuery('translateFrame', ex=1, n=place2dTexture)): try: cov = mc.getAttr(place2dTexture + '.coverage')[0] trans = mc.getAttr(place2dTexture + '.translateFrame')[0] except Exception as e: LOGGER.exception(e) coverage = cov if cov else (1.0, 1.0) translation = (trans[0], trans[1]) if trans and trans else (0, 0) if not WIDGETS['UVEditorTransparencyToggle'].isChecked() and not WIDGETS['UVEditorAlphaOnlyToggle'].isChecked(): alphaPath = None if texturePath: _, ext = os.path.splitext(texturePath) try: # Python 3 supportedFormats = list([str(x, encoding='ASCII').lower() for x in QtGui.QImageReader.supportedImageFormats()]) except BaseException: # Python 2 fallback supportedFormats = list([str(x).decode('ASCII').lower() for x in QtGui.QImageReader.supportedImageFormats()]) if ext and (ext[1:].lower() not in supportedFormats): MESSAGE.warning( "{} format is not supported. Use JPG/JPEG, PNG, TIF/TIFF (LZW or No Compression), TGA (24bit, no RLE)".format(ext[1:].upper())) return err = self.editor.setTexture('%s' % texturePath, alphaPath, coverage, translation) if err == 'SamePath': return elif err == 'NoTexture': MESSAGE.warning("Texture file could not be loaded.") return elif err == 'ZeroTexture': MESSAGE.warning("Invalid Path or Zero Texture") return def manualCurveUpdate(self): try: self._updateCurves() except Exception as e: LOGGER.exception(e) finally: self._stopCurvesUpdate() def _updateCurves(self): if self.uvUpdateCheck == 0: mc.undoInfo(ock=1, cn='gsUVUpdate') self.uvUpdateCheck = 1 sel = mc.filterExpand(mc.ls(sl=1), sm=9) uvs = self.editor.getUVs() self.currentSelection *= 0 if not sel: return for curve in sel: if curve in uvs: self.currentSelection.append(curve) else: if (mc.attributeQuery('gsmessage', n=curve, ex=1) and mc.listConnections(curve + '.gsmessage')): boundCurves = core.getAllConnectedCurves(curve) if boundCurves: self.currentSelection += boundCurves if not self.timer.increment(1.0 / 60.0): return if not self.currentSelection: return uvs = self.editor.getUVs() for curve in self.currentSelection: if curve in uvs: core.attributes.setAttr(curve, uvs[curve]) def _stopCurvesUpdate(self): if self.uvUpdateCheck == 1: mc.undoInfo(cck=1) self.uvUpdateCheck = 0 self.currentSelection *= 0 core.curveControlUI.updateUI() def updateButtons(self, controllerMode, scaleMode): buttons = self.controllerGroup.buttons() direction = self.directionSwitch.buttons() if controllerMode == 'SELECT': buttons[0].setChecked(True) elif controllerMode == 'MOVE': buttons[1].setChecked(True) elif controllerMode == 'ROTATE': buttons[2].setChecked(True) elif controllerMode == 'SCALE': buttons[3].setChecked(True) if scaleMode == 'H': direction[0].setChecked(True) else: direction[1].setChecked(True) elif controllerMode == 'DRAW': buttons[4].setChecked(True) def updateControllerMode(self): buttonID = self.controllerGroup.checkedId() scaleID = self.directionSwitch.checkedId() scale = 'H' if buttonID == 0: mode = 'SELECT' elif buttonID == 1: mode = 'MOVE' elif buttonID == 2: mode = 'ROTATE' elif buttonID == 3: mode = 'SCALE' if scaleID == 0: scale = 'H' else: scale = 'V' else: mode = 'DRAW' self.editor.controllerModeChange(mode, scale) def updateItemList(self): sel = mc.filterExpand(mc.ls(sl=1), sm=9) if not sel: self.uvList.clearItemList() return finalDict = {} for curve in sel: if (mc.attributeQuery('Orientation', n=curve, ex=1) and mc.connectionInfo(curve + '.Orientation', isSource=1)): if (mc.attributeQuery('gsmessage', n=curve, ex=1) and mc.listConnections(curve + '.gsmessage')): boundCurves = core.getAllConnectedCurves(curve) finalDict[curve] = boundCurves else: finalDict[curve] = [] self.uvList.updateItemList(finalDict) def updateVisibility(self): itemList = self.uvList.getSelection() items = self.editor.getAllUVs() for item in items: if item.name in itemList: item.setVisible(True) else: item.setVisible(False) self.editor.update() def hide(self): """Hides selected UV items""" selUVs = self.editor.getAllUVs(selected=True) selUVsList = [i.name for i in selUVs] for uv in selUVs: uv.setVisible(False) itemList = self.uvList.getItemList() selectList = [] for item in itemList: if item.curveName in selUVsList: selectList.append(item) self.uvList.selectItems(selectList) def isolateSelect(self): allUVs = self.editor.getAllUVs() selUVs = self.editor.getAllUVs(selected=True) if not selUVs: return if self.isolateMode: self.showAll() self.isolateMode = False return self.isolateMode = True selUVsList = [i.name for i in selUVs] for uv in allUVs: if uv.name not in selUVsList: uv.setVisible(False) itemList = self.uvList.getItemList() deselectList = [] for item in itemList: if item.curveName not in selUVsList: deselectList.append(item) self.uvList.selectItems(deselectList) def horizontalFlipUV(self): items = self.editor.getAllUVs(selected=True) for item in items: if item.name and mc.attributeQuery('flipUV', n=item.name, ex=1): flip = mc.getAttr(item.name + '.flipUV') mc.setAttr(item.name + '.flipUV', not flip) item.flip = flip item.update() if items: self.editor.update() def verticalFlipUV(self): self.editor.verticalFlipUV() self.manualCurveUpdate() def functionSwitch(self, key): if key == 'H': self.horizontalFlipUV() elif key == 'V': self.verticalFlipUV() elif key == 'X': self.resetUVs() elif key == 'I': self.isolateSelect() elif key == 'O': self.hide() elif key == 'A': self.showAll() elif key == 'S': self.syncSelection() def resetUVs(self): self.editor.resetUV() self.manualCurveUpdate() def randomizeUVs(self): if utils.getMod() == 'Shift': self.editor.randomizeUVs(True) else: self.editor.randomizeUVs(False) self.manualCurveUpdate() def syncSelection(self): """Selects curves in Maya Viewport based on UV Editor selection""" sel = mc.filterExpand(mc.ls(sl=1), sm=9) if not sel: return selUVs = [x.name for x in self.editor.getAllUVs(selected=True)] newSel = [x for x in sel if x in selUVs] if newSel: mc.select(newSel, r=1) @utils.deferredLp def x(): uvs = self.editor.getAllUVs() for uv in uvs: uv.setSelected(True) self.editor.scene().update() x() uveditor = UVEditor('uveditor') # Colors Window class CustomLayerColors: def window(self, *_): self.windowName = 'GSCT_CustomLayerColorsWindow' if mc.workspaceControl(self.windowName, q=1, ex=1): mc.deleteUI(self.windowName) popOut = CreatePopOut(self.windowName, "Layers Customization", 280, 586) layout = popOut.widgetLayout layout.setAlignment(QtCore.Qt.AlignTop) letters = [chr(l) for l in range(ord('A'), ord('A') + 10)] wrap.Label(layout).setLabel("Color Controls:") with wrap.Frame(layout, label='Gradient', margins=[2, 2, 2, 2]) as generateFrame: self.gradientRowsNumber = wrap.ControlSlider(generateFrame.getFrameLayout()) self.gradientRowsNumber.setLabel('Rows') self.gradientRowsNumber.setMinMax(1, 80) self.gradientRowsNumber.setValue(20) with wrap.Row(generateFrame.getFrameLayout()) as gradientColorsLayout: self.minGradientSwatch = wrap.ColorPicker('gradientSwatchMin', gradientColorsLayout.layout()) self.minGradientSwatch.setHSVColors([0.1, 1, 1]) self.maxGradientSwatch = wrap.ColorPicker('gradientSwatchMax', gradientColorsLayout.layout()) self.maxGradientSwatch.setHSVColors([300, 1, 1]) generateGradient = wrap.Button(generateFrame.getFrameLayout(), 'gsGenerateLayerColorGradient') generateGradient.setLabel('Generate Gradient') generateGradient.clicked.connect(self.generateColorGradient) with wrap.Frame(layout, label='Randomize', margins=[2, 2, 2, 2]) as randomizeFrame: self.saturationMin = wrap.ControlSlider(randomizeFrame.getFrameLayout(), typ='float') self.saturationMin.setMinMax(0, 1) self.saturationMin.setValue(0.8) self.saturationMin.setStep(0.01) self.saturationMin.setLabel('SatMin') self.saturationMax = wrap.ControlSlider(randomizeFrame.getFrameLayout(), typ='float') self.saturationMax.setMinMax(0, 1) self.saturationMax.setValue(1.0) self.saturationMax.setStep(0.01) self.saturationMax.setLabel('SatMax') randomizeButton = wrap.Button(randomizeFrame.getFrameLayout(), 'gsRandomizeLayerColors') randomizeButton.setLabel('Randomize All') randomizeButton.clicked.connect(self.randomizeAllColors) layout.addWidget(wrap.separator()) wrap.Label(layout).setLabel("Layers:") def colorRow(parent, i): with wrap.Row(parent) as singleColor: singleColor.setFixedHeight(style.scale(16)) label = wrap.Label() if 10 <= i < 20: label.setLabel('%s (%s)' % (i, letters[i - 10])) else: label.setLabel(str(i)) label.setFixedWidth(style.scale(int(35))) layerName = wrap.LineEdit('layerCustomName_%s' % i) newFont = QtGui.QFont('Roboto') newFont.setPointSizeF(style.scale(5)) layerName.setFixedHeight(style.scale(18)) layerName.setFrame(False) layerName.setFont(newFont) layerName.setAutoFormat(True) layerName.setClearButtonEnabled(True) swatch = wrap.ColorPicker('layerColorPicker_%s' % i) randButton = wrap.Button() randButton.setButtonStyle('small-filled') randButton.setLabel('Rand', lineHeight=100) randButton.setLabelStyle('small') randButton.setWidthHeight(h=style.scale(10)) randButton.clicked.connect(pa(self.randomizeColor, swatch)) resetButton = wrap.Button() resetButton.setButtonStyle('small-filled') resetButton.setLabel('Reset', lineHeight=100) resetButton.setLabelStyle('small') resetButton.setWidthHeight(h=style.scale(10)) resetButton.clicked.connect(pa(self.resetColor, swatch)) resetButton.clicked.connect(pa(self.resetName, layerName)) singleColor.layout().addWidget(label) singleColor.layout().addWidget(layerName, 3) singleColor.layout().addWidget(swatch, 1) singleColor.layout().addWidget(randButton, 1) singleColor.layout().addWidget(resetButton, 1) return singleColor with wrap.Frame(layout, label='0-19') as frame1: for i in range(20): colorRow(frame1.getFrameLayout(), i) frame1.setCollapsed(False) with wrap.Frame(layout, label='20-39') as frame2: for i in range(20, 40): colorRow(frame2.getFrameLayout(), i) frame2.setCollapsed(True) with wrap.Frame(layout, label='40-79') as frame3: for i in range(40, 80): colorRow(frame3.getFrameLayout(), i) frame3.setCollapsed(True) layout.addWidget(wrap.separator()) wrap.Label(layout).setLabel("Commands:") resetButton = wrap.Button(layout, 'gsResetAllLayerColors') resetButton.setLabel('Reset All') resetButton.clicked.connect(self.resetAll) with wrap.Row(layout) as controlButtons: getCurrent = wrap.Button(controlButtons.layout(), 'gsGetCurrentSceneLayers') getCurrent.setLabel('Get From Scene') getCurrent.clicked.connect(self.getFromLayers) setAsCurrent = wrap.Button(controlButtons.layout(), 'gsSetAsCurrentSceneLayers') setAsCurrent.setLabel('Set To Scene') setAsCurrent.clicked.connect(self.setToLayers) with wrap.Row(layout) as buttonsFrame: loadSaved = wrap.Button(buttonsFrame.layout(), 'gsLoadGlobalLayerPreset') loadSaved.setLabel('Load Preset') loadSaved.clicked.connect(self.loadPreset) saveButton = wrap.Button(buttonsFrame.layout(), 'gsSaveGlobalLayerPreset') saveButton.setLabel('Save As Preset') saveButton.clicked.connect(self.savePreset) self.getFromLayers() def randomizeColor(self, swatch): satMin = self.saturationMin.getValue() satMax = self.saturationMax.getValue() swatch.setRGBColors(core.toggleColor.generateBrightColor(satMin, satMax)) def randomizeAllColors(self): for i in range(80): self.randomizeColor(WIDGETS['layerColorPicker_%s' % i]) def resetColor(self, swatch): swatch.setRGBColors([0, 0, 0]) def resetName(self, field): field.clear() def resetAll(self): for i in range(80): WIDGETS['layerColorPicker_%s' % i].setRGBColors([0, 0, 0]) WIDGETS['layerCustomName_%s' % i].clear() def generateColorGradient(self): rows = self.gradientRowsNumber.getValue() colorMin = self.minGradientSwatch.getHSVColors() colorMax = self.maxGradientSwatch.getHSVColors() for i in range(rows): fraction = i / float(rows) h = mt.lerp(fraction, colorMin[0], colorMax[0]) s = mt.lerp(fraction, colorMin[1], colorMax[1]) v = mt.lerp(fraction, colorMin[2], colorMax[2]) WIDGETS['layerColorPicker_%s' % i].setHSVColors([h, s, v]) def getFromLayers(self): # Getting colors colorDict = core.toggleColor.readColorDict() for key in colorDict: WIDGETS['layerColorPicker_%s' % key].setRGBColors(colorDict[key]) # Getting names core.toggleColor.checkColorStorageNode() nameDict = eval(mc.getAttr(core.toggleColor.STORAGE_NODE + '.layerName')) for key in nameDict: if nameDict[key]: WIDGETS['layerCustomName_%s' % key].setText(nameDict[key]) def getCurrentSwatches(self): colorDict = {} for i in range(80): colorDict[i] = WIDGETS['layerColorPicker_%s' % i].getRGBColors() return colorDict def getCurrentNames(self): core.toggleColor.checkColorStorageNode() nameDict = {} for i in range(80): nameDict[i] = WIDGETS['layerCustomName_%s' % i].text() return nameDict def setToLayers(self): colorDict = self.getCurrentSwatches() core.toggleColor.writeColorDict(colorDict) if WIDGETS['colorMode'].isChecked(): core.toggleColor.updateColors() if WIDGETS['syncCurveColor'].isChecked(): core.toggleColor.syncCurveColors() core.updateMainUI() # Setting names nameDict = self.getCurrentNames() core.toggleColor.checkColorStorageNode() mc.setAttr(core.toggleColor.STORAGE_NODE + '.layerName', str(nameDict), typ='string') def setCurrentSwathes(self, colorDict): for key in colorDict: WIDGETS['layerColorPicker_%s' % key].setRGBColors(colorDict[key]) def setCurrentNames(self, nameDict): for key in nameDict: WIDGETS['layerCustomName_%s' % key].setText(nameDict[key]) def savePreset(self): mc.optionVar(sv=['gsCurveToolsCustomColors', str(self.getCurrentSwatches())]) mc.optionVar(sv=['gsCurveToolsCustomLayerNames', str(self.getCurrentNames())]) def loadPreset(self): colorString = mc.optionVar(q='gsCurveToolsCustomColors') colorDict = eval(colorString) self.setCurrentSwathes(colorDict) nameString = mc.optionVar(q='gsCurveToolsCustomLayerNames') nameDict = eval(nameString) self.setCurrentNames(nameDict) customLayerColors = CustomLayerColors() class CreatePopOut(QtWidgets.QWidget): def __init__(self, name, label, width, height): self.name = name parent = mayaWorkspaceControl(name=name, label=label, retain=False, iw=width, ih=height, widthProperty="free") super(CreatePopOut, self).__init__(parent) self.ui() parent.layout().addWidget(self) def ui(self): self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(*style.scale([5, 5, 5, 5])) self.scrollWidget = QtWidgets.QWidget() self.widgetLayout = QtWidgets.QVBoxLayout(self.scrollWidget) scrollArea = QtWidgets.QScrollArea() scrollArea.setWidget(self.scrollWidget) self.mainLayout.addWidget(scrollArea) # Layout Settings self.widgetLayout.setContentsMargins(0, 0, 0, 0) self.widgetLayout.setSpacing(style.scale(2)) self.widgetLayout.setMargin(0) scrollArea.setFrameShape(QtWidgets.QFrame.NoFrame) scrollArea.setWidgetResizable(True) class About: # Creates "About" and "Contacts" windows def social(self): layout = mc.columnLayout() mc.textFieldButtonGrp( bl='>', bc=pa( utils.openLink, 'https://discord.gg/f4DH6HQ'), l='Discord Server', tx='https://discord.gg/f4DH6HQ') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'https://sladkovsky3d.artstation.com/store'), l='Online Store', tx='https://sladkovsky3d.artstation.com/store') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'http://gs-curvetools.readthedocs.io/'), l='Online Documentation', tx='http://gs-curvetools.readthedocs.io/') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'https://www.twitch.tv/videonomad'), l='Twitch Channel', tx='https://www.twitch.tv/videonomad') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'https://www.youtube.com/GeorgeSladkovsky'), l='YouTube Channel', tx='https://www.youtube.com/GeorgeSladkovsky') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'https://www.artstation.com/sladkovsky3d'), l='ArtStation Portfolio', tx='https://www.artstation.com/sladkovsky3d') mc.textFieldButtonGrp(bl='>', bc=pa(utils.openLink, 'mailto:george.sladkovsky@gmail.com'), l='Contact Email', tx='george.sladkovsky@gmail.com') return layout def socialWindow(self): if (mc.window('gsSocialMedia', ex=1)): mc.deleteUI('gsSocialMedia') mc.window('gsSocialMedia', t='Useful Links:', tlb=1) self.social() mc.showWindow() def aboutWindow(self): if mc.window('gsAboutWindow', ex=1): mc.deleteUI('gsAboutWindow') mc.window('gsAboutWindow', t='About', tlb=1) mc.rowColumnLayout(h=400, co=[1, 'left', 10], cal=([1, 'left'], [2, 'right']), nc=2, cw=[1, 200]) mc.text(al='left', l='Version: \n%s' % core.VERSION) mc.iconTextButton(al='right', w=90, h=80, i=utils.getFolder.icons() + 'gsCurveToolsIcon_logo.png') mc.setParent('..') mc.columnLayout(w=460, h=400) mc.text(w=400, ww=1, al='left', l='License:\nThis collection of code named GS CurveTools is a property of George Sladkovsky\ (Yehor Sladkovskyi) and can not be copied or distributed without his written permission.\ \n\n%s\nGeorge Sladkovsky (Yehor Sladkovskyi)\nAll Rights Reserved\ \n\nAutodesk Maya is a property of Autodesk, Inc.\n' % core.VERSION) mc.text(l='Social Media and Contact Links:\n') self.social() mc.showWindow('gsAboutWindow') about = About() class AttributesFilter: def __init__(self): self.uiName = "GSCT_AttributesFilterPopOut" self.attrs = [ ('Length Divisions', 'lengthDivisions'), ('Dynamic Divisions', 'dynamicDivisions'), ('Width Divisions', 'widthDivisions'), ('Orientation', 'Orientation'), ('Twist', 'Twist'), ('Inverted Twist', 'invTwist'), ('Width', 'Width'), ('WidthX', 'WidthX'), ('WidthZ', 'WidthZ'), ('Taper', 'Taper'), ('Length Lock', 'LengthLock'), ('Length', 'Length'), ('Offset', 'Offset'), ('Profile', 'Profile'), ('Refine', 'curveRefine'), ('Auto Refine', 'autoRefine'), ('Smooth', 'curveSmooth'), ('Normals', 'surfaceNormals'), ('Reverse Normals', 'reverseNormals'), ('Axis Flip', 'AxisFlip'), ('Line Width', 'lineWidth'), ('Sampling', 'samplingAccuracy'), ] self.solidify = [ ('Solidify', 'solidify'), ('Solidify Thickness', 'solidifyThickness'), ('Solidify Divisions', 'solidifyDivisions'), ('Solidify Scale X', 'solidifyScaleX'), ('Solidify Scale Y', 'solidifyScaleY'), ('Solidify Offset', 'solidifyOffset'), ('Solidify Normals', 'solidifyNormals'), ] self.uvs = [ ('Move U', 'moveU'), ('Move V', 'moveV'), ('Rotate UV', 'rotateUV'), ('Scale U', 'scaleU'), ('Scale V', 'scaleV'), ('Flip UV', 'flipUV'), ('Rotate Root UV', 'rotateRootUV'), ('Rotate Tip UV', 'rotateTipUV'), ] self.graphs = [ ('Twist Graph', 'twistCurve'), ('Scale Graph', 'scaleCurve'), ('Profile Graph', 'profileCurve'), ('Twist Magnitude', 'Magnitude'), ('Profile Smoothing', 'profileSmoothing'), ('Profile Magnitude', 'profileMagnitude'), ] def openUI(self): if mc.workspaceControl(self.uiName, q=1, ex=1): if mc.workspaceControl(self.uiName, q=1, vis=1): mc.deleteUI(self.uiName) return else: mc.deleteUI(self.uiName) popOut = CreatePopOut(self.uiName, "Attributes Filter", 260, 456.0) layout = popOut.widgetLayout layout.setAlignment(QtCore.Qt.AlignTop) with wrap.Row(layout, margins=style.scale([6, 0, 6, 0]), spacing=style.scale(10)) as mainRow: mainRow.layout().setAlignment(QtCore.Qt.AlignTop) with wrap.Column(mainRow.layout()) as leftColumn: with wrap.Frame(leftColumn.layout(), label='Attributes', margins=[2, 0, 2, 0]) as leftFrame: leftFrame.setCollapsible(False) leftFrame.getFrameLayout().setAlignment(QtCore.Qt.AlignTop) for i in range(len(self.attrs)): btn = wrap.Button(leftFrame.getFrameLayout(), 'gsFilter_%s' % self.attrs[i][1]) btn.setLabel(self.attrs[i][0]) btn.setButtonStyle('small') btn.setCheckable(True) btn.setChecked(False if self.attrs[i][0] == 'Orientation' else True) with wrap.Column(mainRow.layout()) as rightColumn: rightColumn.layout().setAlignment(QtCore.Qt.AlignTop) with wrap.Frame(rightColumn.layout(), label='Solidify', margins=[2, 0, 2, 0]) as rightFrame1: rightFrame1.setCollapsible(False) rightFrame1.getFrameLayout().setAlignment(QtCore.Qt.AlignTop) for i in range(len(self.solidify)): btn = wrap.Button(rightFrame1.getFrameLayout(), 'gsFilter_%s' % self.solidify[i][1]) btn.setLabel(self.solidify[i][0]) btn.setButtonStyle('small') btn.setCheckable(True) btn.setChecked(True) with wrap.Frame(rightColumn.layout(), label='Graphs', margins=[2, 0, 2, 0]) as rightFrame2: rightFrame2.setCollapsible(False) rightFrame2.getFrameLayout().setAlignment(QtCore.Qt.AlignTop) for i in range(len(self.graphs)): btn = wrap.Button(rightFrame2.getFrameLayout(), 'gsFilter_%s' % self.graphs[i][1]) btn.setLabel(list(self.graphs)[i][0]) btn.setButtonStyle('small') btn.setCheckable(True) btn.setChecked(True) with wrap.Frame(rightColumn.layout(), label='UVs', margins=[2, 0, 2, 0]) as rightFrame3: rightFrame3.setCollapsible(False) rightFrame3.getFrameLayout().setAlignment(QtCore.Qt.AlignTop) for i in range(len(self.uvs)): btn = wrap.Button(rightFrame3.getFrameLayout(), 'gsFilter_%s' % self.uvs[i][1]) btn.setLabel(list(self.uvs)[i][0]) btn.setButtonStyle('small') btn.setCheckable(True) btn.setChecked(True) layout.addWidget(wrap.separator()) with wrap.Row(layout) as confirmCancelLayout: btn = wrap.Button(confirmCancelLayout.layout()) btn.setLabel('Save') btn.clicked.connect(self.saveToOptionVar) btn.clicked.connect(lambda: MESSAGE.printInView("Filters Saved")) btn = wrap.Button(confirmCancelLayout.layout()) btn.setLabel('Close') btn.clicked.connect(self.closeUI) self.updateUI() self.saveToOptionVar() def closeUI(self): if mc.workspaceControl(self.uiName, q=1, ex=1): mc.deleteUI(self.uiName) def updateUI(self): if mc.workspaceControl(self.uiName, q=1, ex=1): controlsDict = self.getFromOptionVar() if controlsDict and isinstance(controlsDict, dict): for key in controlsDict: buttonName = 'gsFilter_%s' % key WIDGETS[buttonName].setChecked(controlsDict[key]) def saveToOptionVar(self): if mc.workspaceControl(self.uiName, q=1, ex=1): allControls = self.attrs + self.graphs + self.uvs + self.solidify controlsDict = {} for control in allControls: buttonName = 'gsFilter_%s' % control[1] button = WIDGETS[buttonName] if buttonName in WIDGETS else None if button: controlsDict.update({control[1]: button.isChecked()}) mc.optionVar(sv=('GSCT_AttributesFilter', str(controlsDict))) def getFromOptionVar(self): if mc.optionVar(ex='GSCT_AttributesFilter'): dictString = mc.optionVar(q='GSCT_AttributesFilter') if dictString: return dict(eval(dictString)) attributesFilter = AttributesFilter() class CardToCurveWindow: def __init__(self): self.uiName = "GSCT_CardToCurvePopOut" self.buttonsDict = {} def openUI(self): if mc.workspaceControl(self.uiName, q=1, ex=1): if mc.workspaceControl(self.uiName, q=1, vis=1): mc.deleteUI(self.uiName) return else: mc.deleteUI(self.uiName) self.buttonsDict = self.loadClickedButtons() self.getBtn = lambda name: self.buttonsDict[name] if name in self.buttonsDict else True popOut = CreatePopOut(self.uiName, "Card to Curve", 245, 271) layout = popOut.widgetLayout layout.setAlignment(QtCore.Qt.AlignTop) self.mainButtonGroup = QtWidgets.QButtonGroup() self.mainButtonGroup.setExclusive(False) self.mainButtonGroup.buttonClicked.connect(self.saveButtonsState) with wrap.Column(layout) as mainColumn: mainColumn.layout().setAlignment(QtCore.Qt.AlignTop) with wrap.Frame(mainColumn.layout(), label='Output Type:', objName='gsCardToCurve_outputTypeSwitch') as outputTypeFrame: outputTypeFrame.setCollapsible(False) outputTypeFrame.setCollapsed(False) with wrap.Row(outputTypeFrame.getFrameLayout()) as outputTypeSwitch: self.outputTypeGroup = QtWidgets.QButtonGroup() WIDGETS['gsCardToCurve_cardTypeGroup'] = self.outputTypeGroup generateCards = wrap.Button(outputTypeSwitch.layout(), 'gsCardToCurve_generateCards') generateCards.setButtonStyle('small') generateCards.setLabel('Cards') generateCards.setCheckable(True) generateCurves = wrap.Button(outputTypeSwitch.layout(), 'gsCardToCurve_generateCurves') generateCurves.setButtonStyle('small') generateCurves.setLabel('Curves Only') generateCurves.setCheckable(True) self.outputTypeGroup.addButton(generateCards, 0) self.outputTypeGroup.addButton(generateCurves, 1) generateCards.setChecked(not mc.optionVar(q='GSCT_CardToCurveOutputType')) generateCurves.setChecked(mc.optionVar(q='GSCT_CardToCurveOutputType')) self.outputTypeGroup.buttonClicked.connect(self.updateActiveButtons) with wrap.Frame(mainColumn.layout(), label='Card Type:', objName="gsCardToCurve_cardType") as cardTypeFrame: self.cardTypeFrame = cardTypeFrame cardTypeFrame.setCollapsible(False) cardTypeFrame.setCollapsed(False) with wrap.Row(cardTypeFrame.getFrameLayout()) as outputTypeSwitch: self.cardTypeGroup = QtWidgets.QButtonGroup() WIDGETS['gsCardToCurve_cardTypeGroup'] = self.cardTypeGroup self.warpCards = wrap.Button(outputTypeSwitch.layout(), 'gsCardToCurve_warp') self.warpCards.setButtonStyle('small') self.warpCards.setLabel('Warp') self.warpCards.setCheckable(True) extrudeCards = wrap.Button(outputTypeSwitch.layout(), 'gsCardToCurve_extrude') extrudeCards.setButtonStyle('small') extrudeCards.setLabel('Extrude') extrudeCards.setCheckable(True) self.cardTypeGroup.addButton(self.warpCards, 0) self.cardTypeGroup.addButton(extrudeCards, 1) self.warpCards.setChecked(not mc.optionVar(q='GSCT_CardToCurveCardType')) extrudeCards.setChecked(mc.optionVar(q='GSCT_CardToCurveCardType')) self.cardTypeGroup.buttonClicked.connect(self.updateActiveButtons) with wrap.Frame(mainColumn.layout(), label='Match Attributes:', objName="gsCardToCurve_matchAttributes") as matchAttributeFrame: self.matchAttributeFrame = matchAttributeFrame matchAttributeFrame.setCollapsible(False) matchAttributeFrame.setCollapsed(False) with wrap.Row(matchAttributeFrame.getFrameLayout()) as row: orientation = wrap.Button(row.layout(), 'gsCardToCurve_orientation') orientation.setButtonStyle('small') orientation.setLabel('Orientation') orientation.setCheckable(True) orientation.setChecked(self.getBtn('gsCardToCurve_orientation')) width = wrap.Button(row.layout(), 'gsCardToCurve_width') width.setButtonStyle('small') width.setLabel('Width') width.setCheckable(True) width.setChecked(self.getBtn('gsCardToCurve_width')) self.mainButtonGroup.addButton(orientation) self.mainButtonGroup.addButton(width) with wrap.Row(matchAttributeFrame.getFrameLayout()) as row: taper = wrap.Button(row.layout(), 'gsCardToCurve_taper') taper.setButtonStyle('small') taper.setLabel('Taper') taper.setCheckable(True) taper.setChecked(self.getBtn('gsCardToCurve_taper')) twist = wrap.Button(row.layout(), 'gsCardToCurve_twist') twist.setButtonStyle('small') twist.setLabel('Twist') twist.setCheckable(True) twist.setChecked(self.getBtn('gsCardToCurve_twist')) self.mainButtonGroup.addButton(taper) self.mainButtonGroup.addButton(twist) with wrap.Row(matchAttributeFrame.getFrameLayout()) as row: profile = wrap.Button(row.layout(), 'gsCardToCurve_profile') profile.setButtonStyle('small') profile.setLabel('Profile') profile.setCheckable(True) profile.setChecked(self.getBtn('gsCardToCurve_profile')) material = wrap.Button(row.layout(), 'gsCardToCurve_material') material.setButtonStyle('small') material.setLabel('Material') material.setCheckable(True) material.setChecked(self.getBtn('gsCardToCurve_material')) self.mainButtonGroup.addButton(profile) self.mainButtonGroup.addButton(material) UVs = wrap.Button(matchAttributeFrame.getFrameLayout(), 'gsCardToCurve_UVs') UVs.setButtonStyle('small') UVs.setLabel('UVs') UVs.setCheckable(True) UVs.setChecked(self.getBtn('gsCardToCurve_UVs')) UVs.clicked.connect(self.updateActiveButtons) self.mainButtonGroup.addButton(UVs) with wrap.Frame(mainColumn.layout(), label='UV Match Options:', objName="gsCardToCurve_UVMatchOptions") as uvMatchOptionsFrame: self.uvMatchOptionsFrame = uvMatchOptionsFrame uvMatchOptionsFrame.setCollapsible(False) uvMatchOptionsFrame.setCollapsed(False) with wrap.Row(uvMatchOptionsFrame.getFrameLayout()) as row: verticalFlip = wrap.Button(row.layout(), 'gsCardToCurve_verticalFlip') verticalFlip.setButtonStyle('small') verticalFlip.setLabel('Vertical Flip') verticalFlip.setCheckable(True) verticalFlip.setChecked(self.getBtn('gsCardToCurve_verticalFlip')) horizontalFlip = wrap.Button(row.layout(), 'gsCardToCurve_horizontalFlip') horizontalFlip.setButtonStyle('small') horizontalFlip.setLabel('Horizontal Flip') horizontalFlip.setCheckable(True) horizontalFlip.setChecked(self.getBtn('gsCardToCurve_horizontalFlip')) self.mainButtonGroup.addButton(verticalFlip) self.mainButtonGroup.addButton(horizontalFlip) with wrap.Frame(mainColumn.layout(), label='Other:') as otherOptionsFrame: otherOptionsFrame.setCollapsible(False) otherOptionsFrame.setCollapsed(False) reverseCurve = wrap.Button(otherOptionsFrame.getFrameLayout(), 'gsCardToCurve_reverseCurve') reverseCurve.setButtonStyle('small') reverseCurve.setLabel('Reverse Curve') reverseCurve.setCheckable(True) reverseCurve.setChecked(self.getBtn('gsCardToCurve_reverseCurve')) self.mainButtonGroup.addButton(reverseCurve) mainColumn.layout().addWidget(wrap.separator()) with wrap.Row(mainColumn.layout(), margins=style.scale([0, 3, 0, 3])) as _: pass mainColumn.layout().addWidget(wrap.separator()) with wrap.Row(mainColumn.layout()) as row: convertSelected = wrap.Button(row.layout(), objName="gsCardToCurve_convertSelected") convertSelected.setLabel('Convert Selected') convertSelected.clicked.connect(undo(core.cardToCurve)) cancel = wrap.Button(row.layout()) cancel.setLabel('Cancel') cancel.clicked.connect(self.closeUI) self.updateActiveButtons() self.saveButtonsState() def closeUI(self): self.saveButtonsState() if mc.workspaceControl(self.uiName, q=1, ex=1): if mc.workspaceControl(self.uiName, q=1, vis=1): mc.deleteUI(self.uiName) else: mc.deleteUI(self.uiName) def updateActiveButtons(self): if self.outputTypeGroup.checkedId() == 1: self.matchAttributeFrame.setEnabled(False) self.uvMatchOptionsFrame.setEnabled(False) self.cardTypeFrame.setEnabled(False) mc.optionVar(iv=['GSCT_CardToCurveOutputType', 1]) else: mc.optionVar(iv=['GSCT_CardToCurveOutputType', 0]) mc.optionVar(iv=['GSCT_CardToCurveCardType', int(not self.warpCards.isChecked())]) self.matchAttributeFrame.setEnabled(True) self.cardTypeFrame.setEnabled(True) if WIDGETS['gsCardToCurve_UVs'].isChecked(): self.uvMatchOptionsFrame.setEnabled(True) else: self.uvMatchOptionsFrame.setEnabled(False) def saveButtonsState(self): buttons = self.mainButtonGroup.buttons() buttonsDict = {} for b in buttons: buttonsDict.update({b.objName: b.isChecked()}) mc.optionVar(sv=['GSCT_CardToCurveOptions', str(buttonsDict)]) def loadClickedButtons(self): return eval(mc.optionVar(q='GSCT_CardToCurveOptions')) cardToCurveWindow = CardToCurveWindow() def scaleFactorWindow(): windowName = SCALE_FACTOR_UI if mc.workspaceControl(windowName, q=1, ex=1): mc.deleteUI(windowName) popOut = CreatePopOut(windowName, "Scale Factor", 300, 95) layout = popOut.widgetLayout scaleFactor = core.getScaleFactor() m_slider = mc.floatSliderGrp('GSCT_scaleFactorSlider', pre=3, ss=0.01, min=0.01, max=10, fmn=0.001, fmx=1000, f=1, v=scaleFactor ) wrap.MayaSlider(m_slider, layout=layout) with wrap.Row(layout) as row: saveButton = wrap.Button(row.layout()) saveButton.setLabel('Save') saveButton.clicked.connect(pa(core.saveScaleFactor, windowName, False)) saveButton.clicked.connect(updateScaleFactorWindow) saveAndCloseButton = wrap.Button(row.layout()) saveAndCloseButton.setLabel('Save & Close') saveAndCloseButton.clicked.connect(pa(core.saveScaleFactor, windowName)) cancelButton = wrap.Button(row.layout()) cancelButton.setLabel('Cancel') cancelButton.clicked.connect(lambda: mc.deleteUI(windowName)) layout.addWidget(wrap.separator()) with wrap.Row(layout) as row: with wrap.Row(row.layout(), margins=style.scale([2, 0, 2, 0])) as globalRow: label = wrap.Label(globalRow.layout()) label.setLabel("Global:") globalValue = mc.optionVar(q=('GSCT_globalScaleFactor')) field = wrap.LineEdit("scaleFactorGlobalValue", globalRow.layout()) field.setText(str(globalValue)) field.setEnabled(False) with wrap.Row(row.layout(), margins=style.scale([2, 0, 2, 0])) as sceneRow: label = wrap.Label(sceneRow.layout()) label.setLabel("Scene:") if mc.objExists('gsScaleFactorStorageNode') and mc.attributeQuery('scaleFactor', n='gsScaleFactorStorageNode', ex=1): sceneValue = mc.getAttr('gsScaleFactorStorageNode.scaleFactor') else: sceneValue = "####" field = wrap.LineEdit("scaleFactorSceneValue", sceneRow.layout()) field.setText(str(sceneValue)) field.setEnabled(False) with wrap.Row(row.layout(), margins=style.scale([2, 0, 2, 0])) as sceneRow: label = wrap.Label(sceneRow.layout()) label.setLabel("Selected:") if mc.objExists('gsScaleFactorStorageNode') and mc.attributeQuery('scaleFactor', n='gsScaleFactorStorageNode', ex=1): sceneValue = mc.getAttr('gsScaleFactorStorageNode.scaleFactor') else: sceneValue = "####" field = wrap.LineEdit("scaleFactorSelectedValue", sceneRow.layout()) field.setText(str(sceneValue)) field.setEnabled(False) from . import main main.checkScriptJobs(SCALE_FACTOR_UI) def updateScaleFactorWindow(): WIDGETS["scaleFactorGlobalValue"].setText(str(mc.optionVar(q=('GSCT_globalScaleFactor')))) if mc.objExists('gsScaleFactorStorageNode') and mc.attributeQuery('scaleFactor', n='gsScaleFactorStorageNode', ex=1): sceneValue = mc.getAttr('gsScaleFactorStorageNode.scaleFactor') else: sceneValue = "####" WIDGETS["scaleFactorSceneValue"].setText(str(sceneValue)) def scaleFactorConversionDialog(): MESSAGE.warningInView('Curves Without Scale Factor Detected') dialog = mc.confirmDialog( title='No Scale Factor', message='Curves without scale factor detected\nThose Curves were created before v1.2.7 and might not convert correctly', icon='warning', button=['Skip Old Curves', 'Convert All', 'Cancel'], cancelButton='Cancel', dismissString='Cancel' ) if dialog == 'Cancel': return None if dialog == 'Skip Old Curves': return 'Skip' if 'Convert All': return 'All' def curveThicknessWindow(): name = 'GSCT_CurveThicknessWindow' if mc.workspaceControl(name, q=1, ex=1): mc.deleteUI(name) popOut = CreatePopOut(name, "Curve Thickness", 300, 65) layout = popOut.widgetLayout layout.setAlignment(QtCore.Qt.AlignTop) m_slider = mc.floatSliderGrp('GSCT_curveThicknessSlider', pre=3, ss=0.01, min=-1, max=10, fmn=0.001, fmx=1000, f=1, v=mc.optionVar(q='GSCT_globalCurveThickness') ) wrap.MayaSlider(m_slider, layout=layout) with wrap.Row(layout, margins=style.scale([0, 5, 0, 0])) as row: def save(): mc.optionVar(fv=('GSCT_globalCurveThickness', mc.floatSliderGrp('GSCT_curveThicknessSlider', q=1, v=1))) mc.deleteUI(name) def update(): mc.optionVar(fv=('GSCT_globalCurveThickness', mc.floatSliderGrp('GSCT_curveThicknessSlider', q=1, v=1))) core.updateLayerThickness() saveButton = wrap.Button(row.layout()) saveButton.setLabel('Save') saveButton.clicked.connect(save) updateCurves = wrap.Button(row.layout()) updateCurves.setLabel('Update Curves') updateCurves.clicked.connect(update) cancelButton = wrap.Button(row.layout()) cancelButton.setLabel('Cancel') cancelButton.clicked.connect(lambda: mc.deleteUI(name)) def randomizeCurveWindow(): name = "GSCT_RandomizeCurvePopOut" if mc.workspaceControl(name, q=1, ex=1): if mc.workspaceControl(name, q=1, vis=1): mc.deleteUI(name) return else: mc.deleteUI(name) popOut = CreatePopOut(name, "Randomize Curve", 270, 565) layout = popOut.widgetLayout layout.setAlignment(QtCore.Qt.AlignTop) def release(slider, *_): core.sliders.randSliderDrag(slider) core.sliders.randSliderRelease(slider) core.sliders.release() # Control Points with wrap.Frame(layout, label='Control Points') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider0') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveCVsRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) with wrap.Row(frame.getFrameLayout()) as row: lockFirst = wrap.Button(row.layout(), 'gsLockFirstCV') lockFirst.setLabel('Lock First CV', lineHeight=100) lockFirst.setButtonStyle('small') lockFirst.setCheckable(True) lockLast = wrap.Button(row.layout(), 'gsLockLastCV') lockLast.setLabel('Lock Last CV', lineHeight=100) lockLast.setButtonStyle('small') lockLast.setCheckable(True) with wrap.Row(frame.getFrameLayout()) as row: axisX = wrap.Button(row.layout(), 'gsRandAxisX') axisX.setLabel('X', lineHeight=100) axisX.setButtonStyle('small') axisX.setCheckable(True) axisY = wrap.Button(row.layout(), 'gsRandAxisY') axisY.setLabel('Y', lineHeight=100) axisY.setButtonStyle('small') axisY.setCheckable(True) axisZ = wrap.Button(row.layout(), 'gsRandAxisZ') axisZ.setLabel('Z', lineHeight=100) axisZ.setButtonStyle('small') axisZ.setCheckable(True) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveCVsRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 0), cc=pa(release, 0), ), layout=frame.getFrameLayout() ) # Rotation with wrap.Frame(layout, label='Rotation') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider1') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveRotationRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) with wrap.Row(frame.getFrameLayout()) as row: axisX = wrap.Button(row.layout(), 'gsRandRotateAxisX') axisX.setLabel('X', lineHeight=100) axisX.setButtonStyle('small') axisX.setCheckable(True) axisY = wrap.Button(row.layout(), 'gsRandRotateAxisY') axisY.setLabel('Y', lineHeight=100) axisY.setButtonStyle('small') axisY.setCheckable(True) axisZ = wrap.Button(row.layout(), 'gsRandRotateAxisZ') axisZ.setLabel('Z', lineHeight=100) axisZ.setButtonStyle('small') axisZ.setCheckable(True) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveRotationRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 1), cc=pa(release, 1), ), layout=frame.getFrameLayout() ) # Orientation with wrap.Frame(layout, label='Orientation') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider2') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveOrientationRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveOrientationRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 2), cc=pa(release, 2), ), layout=frame.getFrameLayout() ) # Twist with wrap.Frame(layout, label='Twist') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider3') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveTwistRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveTwistRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 3), cc=pa(release, 3), ), layout=frame.getFrameLayout() ) # Width with wrap.Frame(layout, label='Width') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider4') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveWidthRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) uniform = wrap.Button(frame.getFrameLayout(), 'gsWidthCheckBoxUniform') uniform.setButtonStyle('small') uniform.setLabel('Uniform', lineHeight=100) uniform.setCheckable(True) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveWidthRand', min=0.001, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 4), cc=pa(release, 4), ), layout=frame.getFrameLayout() ) # Taper with wrap.Frame(layout, label='Taper') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider5') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveTaperRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveTaperRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 5), cc=pa(release, 5), ), layout=frame.getFrameLayout() ) # Profile with wrap.Frame(layout, label='Profile') as frame: frame.setCollapsible(False) with wrap.Row(frame.getFrameLayout()) as row: enable = wrap.Button(row.layout(), 'curveRandomizeSlider6') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) slider = wrap.mayaSlider(mc.floatSliderGrp('gsCurveProfileRandMulti', l='Mult:', min=1, max=50, pre=1, step=0.5, cw=[(1, 30), (2, 1)])) row.layout().addWidget(slider) uniform = wrap.Button(frame.getFrameLayout(), 'gsProfileCheckBoxNegative') uniform.setButtonStyle('small') uniform.setLabel('Allow Negative Values', lineHeight=100) uniform.setCheckable(True) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveProfileRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 6), cc=pa(release, 6), ), layout=frame.getFrameLayout() ) # Selection with wrap.Frame(layout, label='Selection') as frame: frame.setCollapsible(False) enable = wrap.Button(frame.getFrameLayout(), 'curveRandomizeSlider7') enable.setLabel('Enabled', lineHeight=100) enable.setButtonStyle('small') enable.setCheckable(True) wrap.MayaSlider( mc.floatSliderGrp( 'gsCurveSelectRand', min=0, max=1, step=0.05, dc=pa(core.sliders.randSliderDrag, 7), cc=pa(release, 7), ), layout=frame.getFrameLayout() ) layout.addWidget(wrap.separator()) with wrap.Row(layout) as row: def randomizeClick(): core.sliders.randSliderDrag(-1) core.sliders.randSliderRelease(-1) core.sliders.release() randomize = wrap.Button(row.layout()) randomize.setLabel("Randomize") randomize.clicked.connect(randomizeClick) close = wrap.Button(row.layout()) close.setLabel("Close") close.clicked.connect(lambda: mc.deleteUI(name))