This commit is contained in:
2025-12-07 23:00:40 +08:00
parent 52ac5cf5a6
commit 2cf75f21f4
807 changed files with 2318015 additions and 0 deletions

View File

@@ -0,0 +1,396 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import json
import maya.standalone as std
import maya.cmds as cmds
std.initialize(name='python')
# set up axis to z
cmds.upAxis(ax='z')
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def fbx_export():
# log some basic info about incoming data
sys.stdout.write("Opening File:\n")
sys.stdout.write(str(sys.argv[1]))
sys.stdout.write("Export Data File:\n\n")
sys.stdout.write(str(sys.argv[2]))
sys.stdout.write("\n\n")
# open the maya file
cmds.file(str(sys.argv[1]), open=True, ignoreVersion=True, force=True, prompt=False)
# load data back into dict format
f = open(str(sys.argv[2]), 'r')
sys.stdout.write(str(f))
data = json.load(f)
f.close()
# the data is a dictionary of characters and their export information. That data might look like:
# character: [[seq1 data], [seq2 data]]
# we need to go through each character's data, go through each sequence, and export that sequence out
for character in data:
sequences = data.get(character)
sys.stdout.write("\n\n")
sys.stdout.write(str(sequences))
sys.stdout.write("\n")
sys.stdout.write(str(len(sequences)))
sys.stdout.write("\n")
# sequence data as follows [0-6]:
# Export Meshes? Export Morphs? Export Attrs? Which Morphs? Which Attrs? Pre Script? Path? Post Script? Path?
# Sequence data [7] as follows:
# [character, export?, fbxPath, start, end, fps, rotation interp, sample rate, root export]
# loop through each sequence in the sequence data
for sequence in sequences:
exportMesh = sequence[0]
exportMorphs = sequence[1]
exportAttrs = sequence[2]
morphTargets = sequence[3]
customAttrs = sequence[4]
preScript = sequence[5]
postScript = sequence[6]
sequenceInfo = sequence[7]
# PRE-SCRIPT
if preScript[0]:
sys.stdout.write("\nExecuting Pre-Script...\n")
status = executeScript(preScript[1])
if status:
sys.stdout.write("\nPre-Script successfully executed!\n")
else:
sys.stdout.write("\nPre-Script NOT successfully executed :( \n")
# if this sequence is marked for export
if sequenceInfo[1] == True:
euler = False
quat = True
# get the outputPath
filePath = sequenceInfo[2]
# get the start and end frame
startFrame = sequenceInfo[3]
endFrame = sequenceInfo[4]
# get the fps
fps = sequenceInfo[5]
sys.stdout.write("\n\n" + str(fps) + "\n\n")
cmds.currentUnit(time=str(fps))
cmds.refresh()
# get the rotation interpolation
interp = sequenceInfo[6]
if interp == "Quaternion Slerp":
euler = False
quat = True
if interp == "Independent Euler-Angle":
euler = True
quat = False
# set the fbx export flags
setExportFlags(startFrame, endFrame, euler, quat)
# get the sample rate
sample = sequenceInfo[7]
# get the root export option
rootExport = sequenceInfo[8]
# build selection of what to export
toExport = []
# EXPORT MESHES
if exportMesh:
# get meshes
if cmds.objExists(character + ":ART_RIG_ROOT"):
if cmds.objExists(character + ":ART_RIG_ROOT.LOD_0_Meshes"):
meshes = cmds.listConnections(character + ":ART_RIG_ROOT.LOD_0_Meshes")
for mesh in meshes:
toExport.append(mesh)
# EXPORT MORPHS
if exportMorphs:
for each in morphTargets:
if cmds.objExists(each):
if (each.partition(":")[0]) == character:
conns = cmds.listConnections(each, type="mesh")
if conns is not None:
toExport.extend(conns)
# SKELETON
skeleton = [character + ":root"]
skeleton.extend(reversed(cmds.listRelatives(character + ":root", type='joint', allDescendents=True)))
toExport.append(skeleton[0])
# bake skeleton and blendshapes (using sample rate)
cmds.select(skeleton)
if exportMorphs:
cmds.select(morphTargets, add=True)
# bake down animation onto skeleton and blendshapes
cmds.bakeResults(simulation=True, sb=sample, time=(startFrame, endFrame))
# run euler filter and fix tangents
cmds.select(skeleton)
cmds.filterCurve()
cmds.selectKey()
cmds.keyTangent(itt="linear", ott="linear")
# deal with custom attrs (deleting if user chose not to export)
standardAttrs = ["translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ",
"scaleX", "scaleY", "scaleZ", "visibility"]
if exportAttrs:
available_attrs = cmds.listAttr(skeleton[0], keyable=True)
for attr in available_attrs:
if attr not in standardAttrs:
if (character + ":" + attr) not in customAttrs:
sys.stdout.write("\n\n")
sys.stdout.write("Removing Attr:")
sys.stdout.write(str(attr))
sys.stdout.write("\n\n")
# remove the attribute from the root
cmds.deleteAttr(skeleton[0], at=attr)
# Root Export Options
sys.stdout.write("\n\n" + str(rootExport) + "\n\n")
if rootExport != "Export Root Animation":
if rootExport == "Zero Root":
sys.stdout.write("\nZeroing Out Root Animation\n")
cmds.cutKey(skeleton[0])
attrs = ["translate", "rotate", "scale"]
for attr in attrs:
try:
cmds.disconnectAttr(character + ":driver_root." + attr, character + ":root." + attr)
except Exception as e:
sys.stdout.write("\n" + str(e) + "\n")
for zeroAttr in [".tx", ".ty", ".tz", ".rx", ".ry", ".rz"]:
cmds.setAttr(character + ":root" + zeroAttr, 0)
if rootExport == "Zero Root, Keep World Space":
sys.stdout.write("\nZeroing Out Root Animation, Keeping World Space on rest of rig\n")
# first, find children that need to be locked in place and create a locator for each
rootConnections = cmds.listRelatives(skeleton[0], children=True, type="joint")
lockNodes = []
locators = []
for conn in rootConnections:
lockNodes.append(conn)
constraints = []
for lockNode in lockNodes:
loc = cmds.spaceLocator(name=lockNode + "_loc")[0]
locators.append(loc)
constraint = cmds.parentConstraint(lockNode, loc)[0]
constraints.append(constraint)
sys.stdout.write("Locking down " + lockNode + " to zero out root.")
sys.stdout.write("\n")
# then bake the locators
cmds.select(clear=True)
for lockNode in lockNodes:
cmds.select(lockNode + "_loc", add=True)
cmds.bakeResults(simulation=True, sb=sample, time=(float(startFrame), float(endFrame)))
cmds.delete(constraints)
# reverse the constraints so the bones are constrained to the locator
boneConstraints = []
for lockNode in lockNodes:
con = cmds.parentConstraint(lockNode + "_loc", lockNode)[0]
boneConstraints.append(con)
# disconnect attrs on root bone
attrs = ["translate", "rotate", "scale"]
for attr in attrs:
try:
cmds.disconnectAttr(character + ":driver_root." + attr, character + ":root." + attr)
except Exception as e:
sys.stdout.write("\n" + str(e) + "\n")
# cut keys on the root bone
cmds.cutKey(skeleton[0])
cmds.setAttr(skeleton[0] + ".tx", 0)
cmds.setAttr(skeleton[0] + ".ty", 0)
cmds.setAttr(skeleton[0] + ".tz", 0)
cmds.setAttr(skeleton[0] + ".rx", 0)
cmds.setAttr(skeleton[0] + ".ry", 0)
cmds.setAttr(skeleton[0] + ".rz", 0)
# bake bones now in world space
cmds.select(clear=True)
for lockNode in lockNodes:
cmds.select(lockNode, add=True)
cmds.bakeResults(simulation=True, sb=sample, time=(float(startFrame), float(endFrame)))
cmds.delete(boneConstraints)
# run an euler filter
cmds.select(skeleton)
cmds.filterCurve()
# POST - SCRIPT
if postScript[0]:
sys.stdout.write("\nExecuting Post Script...\n")
status = executeScript(postScript[1])
if status:
sys.stdout.write("\nPost-Script successfully executed!\n")
else:
sys.stdout.write("\nPost-Script NOT successfully executed :( \n")
# EXPORT FBX
cmds.select(toExport)
try:
mel.eval("FBXExport -f \"" + filePath + "\" -s")
except:
cmds.warning("no path specified..")
# close mayapy
os.remove(str(sys.argv[2]))
std.uninitialize()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def setExportFlags(startFrame, endFrame, euler=False, quat=True):
# in 2015, if oneClick isn't loaded, it will throw up an error
try:
cmds.loadPlugin("OneClick.mll")
sys.stdout.write("Loaded OneClick plugin.")
sys.stdout.write("\n")
except Exception as e:
sys.stderr.write("unable to load OneClick plugin.")
sys.stderr.write("\n")
try:
cmds.loadPlugin("fbxmaya.mll")
sys.stdout.write("Loaded FBX plugin.")
sys.stdout.write("\n")
except Exception as e:
sys.stderr.write("unable to load FBX plugin.")
sys.stderr.write("\n")
# Mesh
mel.eval("FBXExportSmoothingGroups -v true")
mel.eval("FBXExportHardEdges -v false")
mel.eval("FBXExportTangents -v false")
mel.eval("FBXExportInstances -v false")
mel.eval("FBXExportInAscii -v true")
mel.eval("FBXExportSmoothMesh -v false")
# Animation
mel.eval("FBXExportBakeComplexAnimation -v true")
mel.eval("FBXExportBakeComplexStart -v " + str(startFrame))
mel.eval("FBXExportBakeComplexEnd -v " + str(endFrame))
mel.eval("FBXExportReferencedAssetsContent -v true")
mel.eval("FBXExportBakeComplexStep -v 1")
mel.eval("FBXExportUseSceneName -v false")
mel.eval("FBXExportFileVersion -v FBX201400")
if euler:
mel.eval("FBXExportQuaternion -v euler")
if quat:
mel.eval("FBXExportQuaternion -v quaternion")
mel.eval("FBXExportShapes -v true")
mel.eval("FBXExportSkins -v true")
mel.eval("FBXExportUpAxis z")
# garbage we don't want
# Constraints
mel.eval("FBXExportConstraints -v false")
# Cameras
mel.eval("FBXExportCameras -v false")
# Lights
mel.eval("FBXExportLights -v false")
# Embed Media
mel.eval("FBXExportEmbeddedTextures -v false")
# Connections
mel.eval("FBXExportInputConnections -v false")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def executeScript(scriptPath):
sourceType = ""
status = False
if scriptPath.find(".py") != -1:
sourceType = "python"
if scriptPath.find(".mel") != -1:
sourceType = "mel"
# MEL
if sourceType == "mel":
try:
command = ""
# open the file, and for each line in the file, add it to our command string.
f = open(scriptPath, 'r')
lines = f.readlines()
for line in lines:
command += line
import maya.mel as mel
mel.eval(command)
# save the file
cmds.file(save=True, type="mayaAscii")
status = True
except:
pass
# PYTHON
if sourceType == "python":
try:
# Python 2/3 compatible way to execute a file
with open(scriptPath, 'r') as f:
exec(f.read())
# save the file
cmds.file(save=True, type="mayaAscii")
status = True
except:
pass
return status
fbx_export()

View File

@@ -0,0 +1,246 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ThirdParty.Qt import QtGui, QtCore, QtWidgets
import importlib
import maya.cmds as cmds
import utils
import System.interfaceUtils as interfaceUtils
import System.git_utils as git
importlib.reload(git)
windowTitle = "ARTv2: Report an Issue"
windowObject = "pyArtReporterWin"
class ART_Reporter(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(ART_Reporter, self).__init__(parent)
#get the directory path of the tools
settings = QtCore.QSettings("Epic Games", "ARTv2")
self.toolsPath = settings.value("toolsPath")
self.iconsPath = settings.value("iconPath")
self.scriptPath = settings.value("scriptPath")
self.projPath = settings.value("projectPath")
#build the UI
self.buildSettingsUi()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def buildSettingsUi(self):
#fonts
self.font = QtGui.QFont()
self.font.setPointSize(10)
self.font.setBold(False)
self.fontSmall = QtGui.QFont()
self.fontSmall .setPointSize(9)
self.fontSmall .setBold(False)
self.titleFont = QtGui.QFont()
self.titleFont.setPointSize(40)
self.titleFont.setBold(True)
#load stylesheet
styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss")
f = open(styleSheetFile, "r")
self.style = f.read()
f.close()
self.setStyleSheet(self.style)
#size policies
mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
#create the main widget
self.mainWidget = QtWidgets.QWidget()
self.mainWidget.setStyleSheet(self.style)
self.mainWidget.setStyleSheet("background-color: rgb(0, 0, 0);, color: rgb(0,0,0);")
self.setCentralWidget(self.mainWidget)
#set qt object name
self.setObjectName(windowObject)
self.setWindowTitle(windowTitle)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
#create the mainLayout for the rig creator UI
self.layout = QtWidgets.QVBoxLayout(self.mainWidget)
self.resize(300, 600)
self.setSizePolicy(mainSizePolicy)
self.setMinimumSize(QtCore.QSize( 300, 600 ))
self.setMaximumSize(QtCore.QSize( 300, 600 ))
#create the QFrame
self.frame = QtWidgets.QFrame()
self.frame.setObjectName("epic")
self.layout.addWidget(self.frame)
self.widgetLayout = QtWidgets.QVBoxLayout(self.frame)
#Title of Issue
self.titleLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.titleLayout)
titleLabel = QtWidgets.QLabel("Title: ")
self.titleLayout.addWidget(titleLabel)
self.issueTitle = QtWidgets.QLineEdit()
self.issueTitle.setPlaceholderText("Title of Issue")
self.titleLayout.addWidget(self.issueTitle)
self.issueTitle.setMinimumWidth(200)
self.issueTitle.setMaximumWidth(200)
#Type of Issue (from labels)
self.labelLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.labelLayout)
typeLabel = QtWidgets.QLabel("Issue Type: ")
self.labelLayout.addWidget(typeLabel)
self.issueType = QtWidgets.QComboBox()
self.labelLayout.addWidget(self.issueType)
self.issueType.setMinimumWidth(200)
self.issueType.setMaximumWidth(200)
#Information
summaryLabel = QtWidgets.QLabel("Summary: ")
self.widgetLayout.addWidget(summaryLabel)
infoText = QtWidgets.QTextEdit()
infoText.setReadOnly(True)
infoText.setEnabled(False)
self.widgetLayout.addWidget(infoText)
infoText.setMinimumHeight(60)
infoText.setMaximumHeight(60)
infoText.setTextColor(QtGui.QColor(120,120,120))
infoText.append("(Please include any errors and stacktrace if applicable. Also include any reproduction steps if possible.)")
self.issueInfo = QtWidgets.QTextEdit()
self.widgetLayout.addWidget(self.issueInfo)
self.issueInfo.setObjectName("light")
#Create Issue
self.createIssueBtn = QtWidgets.QPushButton("Create Issue")
self.createIssueBtn.setObjectName("blueButton")
self.widgetLayout.addWidget(self.createIssueBtn)
self.createIssueBtn.clicked.connect(self.createIssue)
self.credentials = git.getGitCreds()
if self.credentials == None:
git.gitCredsUI(self)
self.credentials = git.getGitCreds()
self.getLabels()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def getLabels(self):
labels = self.githubInfo("label")
ignoreLabel = ["wontfix", "duplicate", "invalid"]
if labels != None:
for label in labels:
if label.name not in ignoreLabel:
self.issueType.addItem(label.name)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def createIssue(self):
title = self.issueTitle.text()
issueType = self.issueType.currentText()
body = "User: " + str(self.credentials[0]) + "\n"
body += "Maya Version: " + str(cmds.about(iv = True)) + "\n"
body += "OS: " + str(cmds.about(os = True)) + "\n" + "\n"
body += self.issueInfo.toPlainText()
repo = self.githubInfo("repo")
issueCreated = False
try:
issue = repo.create_issue(title, body)
issue.set_labels(issueType)
issueCreated = True
except Exception as e:
cmds.warning(f"unable to create issue. Error: {str(e)}")
self.close()
return
if issueCreated:
msgBox = QtWidgets.QMessageBox()
msgBox.setText("Your issue has been created")
msgBox.setDetailedText("To view your issue, please visit:\nhttps://github.com/epicernst/Test/issues")
ret = msgBox.exec_()
self.close()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def githubInfo(self, type):
#github section
# try:
from ThirdParty.github import Github
# except:
# cmds.warning("unable to import github module. You will not be able to create an issue")
# self.close()
# return
repoOwner = "epicernst"
try:
g = Github(self.credentials[0], self.credentials[1])
repo = g.get_user(repoOwner).get_repo("Test")
labels = repo.get_labels()
if type == "repo":
return repo
if type == "label":
return labels
except Exception:
return None
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def run():
if cmds.window("pyArtReporterWin", exists = True):
cmds.deleteUI("pyArtReporterWin", wnd = True)
gui = ART_Reporter(interfaceUtils.getMainWindow())
gui.show()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ThirdParty.Qt import QtGui, QtCore, QtWidgets, QtCompat
# Use shiboken from Qt.py for compatibility
from functools import partial
import maya.cmds as cmds
import os, json
import System.utils as utils
def getMainWindow():
import maya.OpenMayaUI as mui
pointer = mui.MQtUtil.mainWindow()
#pyside QMainWindow takes in a QWidget rather than QObject
return QtCompat.wrapInstance(int(pointer), QtWidgets.QWidget)
windowTitle = "ART_Settings"
windowObject = "pyArtSettingsWin"
class ART_Settings(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(ART_Settings, self).__init__(parent)
#get the directory path of the tools
settings = QtCore.QSettings("Epic Games", "ARTv2")
self.toolsPath = settings.value("toolsPath")
self.scriptPath = settings.value("scriptPath")
self.iconsPath = settings.value("iconPath")
self.projPath = settings.value("projectPath")
#build the UI
self.buildSettingsUi()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def buildSettingsUi(self):
#fonts
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
fontSmall = QtGui.QFont()
fontSmall.setPointSize(9)
fontSmall.setBold(True)
#images
frameBackground = os.path.normcase(os.path.join(self.iconsPath, "System/field_background.png"))
if frameBackground.partition("\\")[2] != "":
frameBackground = frameBackground.replace("\\", "/")
imageBkgrd = os.path.normcase(os.path.join(self.iconsPath, "System/toolbar_background.png"))
if imageBkgrd.partition("\\")[2] != "":
imageBkgrd = imageBkgrd.replace("\\", "/")
imageBtnBkrd = os.path.normcase(os.path.join(self.iconsPath, "System/blue_field_background.png"))
if imageBtnBkrd.partition("\\")[2] != "":
imageBtnBkrd = imageBtnBkrd.replace("\\", "/")
#size policies
mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
#create the main widget
self.mainWidget = QtWidgets.QWidget()
self.mainWidget.setStyleSheet("background-color: rgb(0, 0, 0);, color: rgb(0,0,0);")
self.setCentralWidget(self.mainWidget)
#set qt object name
self.setObjectName(windowObject)
self.setWindowTitle(windowTitle)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
#create the mainLayout for the rig creator UI
self.layout = QtWidgets.QVBoxLayout(self.mainWidget)
self.resize(600, 260)
self.setSizePolicy(mainSizePolicy)
self.setMinimumSize(QtCore.QSize( 600, 260 ))
self.setMaximumSize(QtCore.QSize( 600, 260 ))
#create the QFrame
self.frame = QtWidgets.QFrame()
self.layout.addWidget(self.frame)
self.widgetLayout = QtWidgets.QVBoxLayout(self.frame)
#info page styling
self.frame.setStyleSheet("background-image: url(" + imageBkgrd + ");")
#MayaTools/Core : Sccipts, icons, jointmover, etc
#MayaTools/Projects: actual project files (animation rigs, thumbnails, poses, etc)
#location
self.locationLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.locationLayout)
#location -> label
label = QtWidgets.QLabel("Tools Location: ")
self.locationLayout.addWidget(label)
label.setFont(font)
label.setMinimumWidth(150)
#location -> line edit
path = utils.returnFriendlyPath(self.toolsPath)
self.locationPath = QtWidgets.QLineEdit(path)
self.locationLayout.addWidget(self.locationPath)
self.locationPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);")
self.locationPath.setMinimumHeight(35)
#location -> browse button
self.locationBrowse = QtWidgets.QPushButton()
self.locationLayout.addWidget(self.locationBrowse)
self.locationBrowse.setMinimumSize(35,35)
self.locationBrowse.setMaximumSize(35, 35)
btnBackground = utils.returnNicePath(self.iconsPath, "System/fileBrowse.png")
self.locationBrowse.setStyleSheet("background-image: url(" + btnBackground + ");")
self.locationBrowse.clicked.connect(partial(self.browse, self.locationPath))
#scripts folder
self.scriptsLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.scriptsLayout)
#scripts -> label
label = QtWidgets.QLabel("Scripts: ")
self.scriptsLayout.addWidget(label)
label.setFont(fontSmall)
label.setMinimumWidth(150)
#scripts -> line edit
path = utils.returnFriendlyPath(self.scriptPath)
self.scriptsPath = QtWidgets.QLineEdit(path)
self.scriptsLayout.addWidget(self.scriptsPath)
self.scriptsPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);")
self.scriptsPath.setMinimumHeight(35)
#scripts -> browse button
self.scriptsBrowse = QtWidgets.QPushButton()
self.scriptsLayout.addWidget(self.scriptsBrowse)
self.scriptsBrowse.setMinimumSize(35,35)
self.scriptsBrowse.setMaximumSize(35, 35)
self.scriptsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");")
self.scriptsBrowse.clicked.connect(partial(self.browse, self.scriptsPath))
#icons folder
self.iconsLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.iconsLayout)
#icons -> label
label = QtWidgets.QLabel("Icons: ")
self.iconsLayout.addWidget(label)
label.setFont(fontSmall)
label.setMinimumWidth(150)
#icons -> line edit
path = utils.returnFriendlyPath(self.iconsPath)
self.iconPath = QtWidgets.QLineEdit(path)
self.iconsLayout.addWidget(self.iconPath)
self.iconPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);")
self.iconPath.setMinimumHeight(35)
#icons -> browse button
self.iconsBrowse = QtWidgets.QPushButton()
self.iconsLayout.addWidget(self.iconsBrowse)
self.iconsBrowse.setMinimumSize(35,35)
self.iconsBrowse.setMaximumSize(35, 35)
self.iconsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");")
self.iconsBrowse.clicked.connect(partial(self.browse, self.iconsPath))
#projects folder
self.projectsLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.projectsLayout)
#projects -> label
label = QtWidgets.QLabel("Projects: ")
self.projectsLayout.addWidget(label)
label.setFont(fontSmall)
label.setMinimumWidth(150)
#projects -> line edit
path = utils.returnFriendlyPath(self.projPath)
self.projectsPath = QtWidgets.QLineEdit(path)
self.projectsLayout.addWidget(self.projectsPath)
self.projectsPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);")
self.projectsPath.setMinimumHeight(35)
#projects -> browse button
self.projectsBrowse = QtWidgets.QPushButton()
self.projectsLayout.addWidget(self.projectsBrowse)
self.projectsBrowse.setMinimumSize(35,35)
self.projectsBrowse.setMaximumSize(35, 35)
self.projectsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");")
self.projectsBrowse.clicked.connect(partial(self.browse, self.projectsPath))
#Save button
self.saveChangesBtn = QtWidgets.QPushButton("Save Changes")
self.widgetLayout.addWidget(self.saveChangesBtn)
self.saveChangesBtn.setFont(font)
self.saveChangesBtn.setMinimumHeight(35)
self.saveChangesBtn.setStyleSheet("background-image: url(" + imageBtnBkrd + ");background-color: rgb(25, 175, 255);")
self.saveChangesBtn.clicked.connect(partial(self.saveSettings))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def browse(self, lineEdit):
try:
newPath = cmds.fileDialog2(dir = self.toolsPath, fm = 3)[0]
newPath = utils.returnFriendlyPath(newPath)
lineEdit.setText(newPath)
except Exception:
pass #in case user cancels on Maya's browse dialog
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def saveSettings(self):
#get data from ui
mayaToolsDir = self.locationPath.text()
scriptDir = self.scriptsPath.text()
iconsDir = self.iconPath.text()
projectsDir = self.projectsPath.text()
#save data
settings = QtCore.QSettings("Epic Games", "ARTv2")
settings.setValue("toolsPath", mayaToolsDir)
settings.setValue("scriptPath", scriptDir)
settings.setValue("iconPath", iconsDir)
settings.setValue("projectPath", projectsDir)
#Give message regarding data being saved, but it won't take effect until Maya is restarted.
cmds.confirmDialog(title = "Settings Saved", message = "Please close Maya and reopen in order to have these settings take effect.")
#close UI
if cmds.window("pyArtSettingsWin", exists = True):
cmds.deleteUI("pyArtSettingsWin", wnd = True)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def run():
if cmds.window("pyArtSettingsWin", exists = True):
cmds.deleteUI("pyArtSettingsWin", wnd = True)
gui = ART_Settings(getMainWindow())
gui.show()

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import maya.standalone as std
std.initialize(name = 'python')
import maya.cmds as cmds
import maya.mel as mel
filename = sys.argv[1]
def stripNamespace(filename):
try:
#open the file
cmds.loadPlugin("fbxmaya.mll")
string = "FBXImportMode -v \"add\";"
string += "FBXImport -file \"" + filename + "\""
string += "FBXImportFillTimeline -v true"
mel.eval(string)
#remove the namespace
cmds.namespace(setNamespace = "::")
currentNamespaces = cmds.namespaceInfo(listOnlyNamespaces = True)
restricted = ['UI', 'shared']
for namespace in currentNamespaces:
if namespace not in restricted:
cmds.namespace(mv = (':' + namespace, ':'), force = True)
cmds.namespace(removeNamespace = namespace)
#re-export the file
mel.eval("FBXExport -f \""+ filename +"\"")
#exit
std.uninitialize()
except Exception as e:
sys.stderr.write(str(e))
sys.exit(-1)
stripNamespace(filename)

View File

@@ -0,0 +1,613 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Python 2/3 compatibility
try:
long
except NameError:
# Python 3
long = int
from ThirdParty.Qt import QtGui, QtCore, QtWidgets, QtCompat
import maya.cmds as cmds
import os
import json
import utils
import math
import traceback
import urllib2
import zipfile
import shutil
import errno
import stat
import base64
import System.git_utils as git
# Use shiboken from Qt.py for compatibility
def getMainWindow():
import maya.OpenMayaUI as mui
pointer = mui.MQtUtil.mainWindow()
#pyside QMainWindow takes in a QWidget rather than QObject
return QtCompat.wrapInstance(long(pointer), QtWidgets.QWidget)
windowTitle = "ARTv2: Check For Updates"
windowObject = "pyArtUpdaterWin"
class ART_Updater(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(ART_Updater, self).__init__(parent)
#get the directory path of the tools
settings = QtCore.QSettings("Epic Games", "ARTv2")
self.toolsPath = settings.value("toolsPath")
self.scriptPath = settings.value("scriptPath")
self.iconsPath = settings.value("iconPath")
self.projPath = settings.value("projectPath")
#get github credentials
self.credentials = git.getGitCreds()
if self.credentials == None:
git.gitCredsUI(self)
self.credentials = git.getGitCreds()
#build the UI
self.buildSettingsUi()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def buildSettingsUi(self):
#fonts
self.font = QtGui.QFont()
self.font.setPointSize(10)
self.font.setBold(False)
self.fontSmall = QtGui.QFont()
self.fontSmall .setPointSize(9)
self.fontSmall .setBold(False)
self.titleFont = QtGui.QFont()
self.titleFont.setPointSize(40)
self.titleFont.setBold(True)
#images
frameBackground = os.path.normcase(os.path.join(self.iconsPath, "System/field_background.png"))
if frameBackground.partition("\\")[2] != "":
frameBackground = frameBackground.replace("\\", "/")
imageBkgrd = os.path.normcase(os.path.join(self.iconsPath, "System/toolbar_background.png"))
if imageBkgrd.partition("\\")[2] != "":
imageBkgrd = imageBkgrd.replace("\\", "/")
imageBtnBkrd = os.path.normcase(os.path.join(self.iconsPath, "System/blue_field_background.png"))
if imageBtnBkrd.partition("\\")[2] != "":
imageBtnBkrd = imageBtnBkrd.replace("\\", "/")
#load stylesheet
styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss")
f = open(styleSheetFile, "r")
self.style = f.read()
f.close()
self.setStyleSheet(self.style)
#size policies
mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
#create the main widget
self.mainWidget = QtWidgets.QWidget()
self.mainWidget.setStyleSheet(self.style)
self.mainWidget.setStyleSheet("background-color: rgb(0, 0, 0);, color: rgb(0,0,0);")
self.setCentralWidget(self.mainWidget)
#set qt object name
self.setObjectName(windowObject)
self.setWindowTitle(windowTitle)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
#create the mainLayout for the rig creator UI
self.layout = QtWidgets.QVBoxLayout(self.mainWidget)
self.resize(600, 300)
self.setSizePolicy(mainSizePolicy)
self.setMinimumSize(QtCore.QSize( 600, 300 ))
self.setMaximumSize(QtCore.QSize( 600, 300 ))
#create the QFrame
self.frame = QtWidgets.QFrame()
self.layout.addWidget(self.frame)
self.widgetLayout = QtWidgets.QVBoxLayout(self.frame)
#info page styling
self.frame.setStyleSheet("background-image: url(" + imageBkgrd + ");")
#detailed information
self.infoText = QtWidgets.QTextEdit()
self.infoText.acceptRichText()
self.infoText.setStyleSheet("background-color: rgb(120,120,120); background-image: url(" + frameBackground + ");")
self.widgetLayout.addWidget(self.infoText)
self.infoText.setMinimumSize(QtCore.QSize(550,170))
self.infoText.setMaximumSize(QtCore.QSize(550,170))
self.infoText.setReadOnly(True)
self.infoText.setAutoFormatting(QtWidgets.QTextEdit.AutoBulletList)
self.infoText.setLineWrapMode(QtWidgets.QTextEdit.WidgetWidth)
#progress bar
self.progressBar = QtWidgets.QProgressBar()
self.progressBar.setStyleSheet(self.style)
self.progressBar.setMinimumSize(QtCore.QSize(550, 25))
self.progressBar.setMaximumSize(QtCore.QSize(550, 25))
self.widgetLayout.addWidget(self.progressBar)
#button bar
self.buttonLayout = QtWidgets.QHBoxLayout()
self.widgetLayout.addLayout(self.buttonLayout)
self.cancelButton = QtWidgets.QPushButton("Close")
self.buttonLayout.addWidget(self.cancelButton)
self.cancelButton.setStyleSheet(self.style)
self.cancelButton.setObjectName("blueButton")
self.cancelButton.clicked.connect(self.cancel)
self.updateButton = QtWidgets.QPushButton("Update")
self.buttonLayout.addWidget(self.updateButton)
self.updateButton.setStyleSheet(self.style)
self.updateButton.setObjectName("blueButton")
self.updateButton.clicked.connect(self.downloadUpdates)
if self.credentials != None:
self.getInfo()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def getInfo(self):
#need to eventually swap this with the real file
request = urllib2.Request("https://raw.githubusercontent.com/epicernst/Test/master/ARTv2_VersionInfo.json")
base64String = base64.encodestring('%s:%s' % (self.credentials[0], self.credentials[1])).replace('\n', '')
request.add_header("Authorization", "Basic %s" % base64String)
try:
result = urllib2.urlopen(request)
except Exception as e:
self.infoText.setTextColor(QtGui.QColor(249,241,12))
self.infoText.append(str(e))
self.infoText.append("Your Github login credentials may be invalid or you do not have access to this repo.\n\n")
self.infoText.setTextColor(QtGui.QColor(255,255,255))
settings = QtCore.QSettings("Epic Games", "ARTv2")
settings.remove("gitUser")
settings.remove("gitPass")
return
content = json.loads(result.read())
versions = content.get("versions")
newFeatures = []
majorFixes = []
minorFixes = []
for version in versions:
data = versions.get(version)
for key in data:
if key == "New":
info = data.get(key)
for each in info:
newFeatures.append(each)
if key == "Critical":
info = data.get(key)
for each in info:
majorFixes.append(each)
if key == "Minor":
info = data.get(key)
for each in info:
minorFixes.append(each)
#Compare local version to latest
latestVersion = content.get("latest version")
localVersion = self.checkLocalVersion()
if float(latestVersion) > float(localVersion):
self.infoText.append("You are not up to date!\n")
self.infoText.append("Latest Version: " + str(content.get("latest version")))
self.infoText.append("Local Version: " + str(localVersion))
self.infoText.append("\n")
#release notes
self.infoText.setFont(self.titleFont)
self.infoText.setTextColor(QtGui.QColor(48,255,0))
self.infoText.setAlignment(QtCore.Qt.AlignCenter)
self.infoText.append("|| NEW FEATURES ||")
self.infoText.setFont(self.fontSmall)
self.infoText.setAlignment(QtCore.Qt.AlignLeft)
self.infoText.setTextColor(QtGui.QColor(255,255,255))
for feature in newFeatures:
self.infoText.append(" *" + str(feature))
self.infoText.append("\n")
self.infoText.setFont(self.titleFont)
self.infoText.setTextColor(QtGui.QColor(249,168,12))
self.infoText.setAlignment(QtCore.Qt.AlignCenter)
self.infoText.append("|| MAJOR FIXES ||")
self.infoText.setFont(self.fontSmall)
self.infoText.setAlignment(QtCore.Qt.AlignLeft)
self.infoText.setTextColor(QtGui.QColor(255,255,255))
for fix in majorFixes:
self.infoText.append(" *" + str(fix))
self.infoText.append("\n")
self.infoText.setFont(self.titleFont)
self.infoText.setTextColor(QtGui.QColor(249,241,12))
self.infoText.setAlignment(QtCore.Qt.AlignCenter)
self.infoText.append("|| MINOR FIXES ||")
self.infoText.setFont(self.fontSmall)
self.infoText.setAlignment(QtCore.Qt.AlignLeft)
self.infoText.setTextColor(QtGui.QColor(255,255,255))
for each in minorFixes:
self.infoText.append(" *" + str(each))
self.infoText.moveCursor(QtGui.QTextCursor.Start)
else:
self.infoText.append("You are up-to-date!")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def checkLocalVersion(self):
mayaModDir = os.environ["home"] + "/maya/modules/"
if cmds.about(os = True) == "mac":
mayaModDir = os.environ["home"] + "/Library/Preferences/Autodesk/maya/modules/"
modName = "ARTv2.mod"
modFile = mayaModDir + modName
modFileObj = file(modFile, mode='r')
lines = modFileObj.readlines()
modFileObj.close()
localVersion = float(lines[0].split(" ")[2])
return localVersion
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def checkLatestVersion(self):
info = git.getGitCreds()
if info != None:
user = info[0]
password = info[1]
#need to eventually swap this with the real file
request = urllib2.Request("https://raw.githubusercontent.com/epicernst/Test/master/ARTv2_VersionInfo.json")
base64String = base64.encodestring('%s:%s' % (user, password)).replace('\n', '')
request.add_header("Authorization", "Basic %s" % base64String)
result = urllib2.urlopen(request)
content = json.loads(result.read())
latestVersion = content.get("latest version")
return latestVersion
else:
self.invalidCreds()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def updateLocalVersion(self):
info = git.getGitCreds()
if info != None:
mayaModDir = cmds.internalVar(uad = True)
mayaModDir = os.path.join(mayaModDir, "modules")
mayaModDir = utils.returnFriendlyPath(os.path.join(mayaModDir, "ARTv2.mod"))
if os.path.exists(mayaModDir):
f = open(mayaModDir, 'r')
line = f.readline()
f.close()
if line.find("+ ARTv2 ") != -1:
version = line.partition("+ ARTv2 ")[2].partition(" ")[0]
latest = self.checkLatestVersion()
newline = line.replace(str(version), str(latest))
f = open(mayaModDir, 'w')
f.write(newline)
f.close()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def findReadOnlyFiles(self, fullPath, listOfFiles):
#list file contents
contents = os.listdir(fullPath)
for each in contents:
if os.path.isfile(os.path.join(fullPath, each)):
fileAttr = os.stat(os.path.join(fullPath, each)).st_mode
if not fileAttr & stat.S_IWRITE:
try:
os.chmod(os.path.join(fullPath, each), stat.S_IWRITE)
except Exception as e:
listOfFiles.append([each, e])
if os.path.isdir(os.path.join(fullPath, each)):
self.findReadOnlyFiles(os.path.join(fullPath, each), listOfFiles)
return listOfFiles
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def downloadUpdates(self):
info = git.getGitCreds()
if info != None:
user = info[0]
password = info[1]
else:
self.invalidCreds()
return
base64String = base64.encodestring('%s:%s' % (user, password)).replace('\n', '')
opener = urllib2.build_opener()
opener.addheaders = [("Authorization", "Basic %s" % base64String)]
response = opener.open("https://github.com/epicernst/Test/archive/master.zip")
zipContent = response.read()
filename = os.path.basename("https://github.com/epicernst/Test/blob/master/master.zip")
path = os.environ["home"]
filePath = os.path.join(path, filename)
with open(filePath, 'w') as f:
f.write(zipContent)
masterDir = os.path.dirname(filePath)
mayaToolsZip = masterDir
with zipfile.ZipFile(filePath, 'r') as zfile:
for name in zfile.namelist():
if name.find(".zip") != -1:
mayaToolsZip = os.path.join(mayaToolsZip, name)
zfile.extractall(masterDir)
baseToolsDir = os.path.dirname(self.toolsPath)
wholeCopy = False
fileIssues = []
with zipfile.ZipFile(mayaToolsZip) as zf:
removeDirs = ["MayaTools/Core/Scripts/", "MayaTools/Core/Icons/", "MayaTools/Core/JointMover/", "MayaTools/plug-ins/"]
#set progress bar range
self.progressBar.setMaximum(len(removeDirs) + 1)
self.progressBar.setValue(0)
for dir in removeDirs:
fullPath = os.path.normpath(os.path.join(baseToolsDir, dir))
#list file contents
readOnlyFiles = self.findReadOnlyFiles(fullPath, fileIssues)
#if readOnlyFiles is empty
if len(readOnlyFiles) == 0:
#make a back-up of local versions
self.infoText.setTextColor(QtGui.QColor(0,0,0))
self.infoText.append("\n########################################################\n")
self.infoText.setTextColor(QtGui.QColor(255,255,255))
self.infoText.append("Creating Backup of current version.. " + str(dir))
self.infoText.moveCursor(QtGui.QTextCursor.End)
versionNumber = self.checkLocalVersion()
backupDir = os.path.join(os.path.dirname(self.toolsPath), "ARTv2/Backups")
backupDir = os.path.normpath(os.path.join(backupDir, str(versionNumber)))
printDir = backupDir
backupDir = utils.returnFriendlyPath(backupDir)
if not os.path.exists(backupDir):
os.makedirs(backupDir)
fullPath = utils.returnFriendlyPath(fullPath)
try:
shutil.move(fullPath, backupDir)
self.infoText.append(" Backups created in " + str(printDir))
self.infoText.moveCursor(QtGui.QTextCursor.End)
except Exception as e:
self.infoText.setTextColor(QtGui.QColor(249,168,12))
self.infoText.append(str(e))
self.infoText.setTextColor(QtGui.QColor(255,255,255))
wholeCopy = True
#extract zip file directory to original location
if wholeCopy == False:
for name in zf.namelist():
for each in removeDirs:
if name.find(each)!= -1:
#extract directly to the base location
try:
zf.extract(name, baseToolsDir)
except Exception as e:
self.infoText.setTextColor(QtGui.QColor(249,168,12))
self.infoText.append(str(e))
self.infoText.setTextColor(QtGui.QColor(255,255,255))
wholeCopy = True
self.infoText.append(" Extracted updated files to " + str(dir))
self.infoText.moveCursor(QtGui.QTextCursor.End)
#report on operations
value = self.progressBar.value()
self.progressBar.setValue(value + 1)
#if readOnlyFiles is not empty
else:
wholeCopy = True
if len(readOnlyFiles) > 0:
self.infoText.append("The following files were marked as read-only and could not be updated:")
for file in readOnlyFiles:
self.infoText.append(" " + str(file))
self.infoText.moveCursor(QtGui.QTextCursor.End)
if wholeCopy:
#report issues in UI
self.infoText.setTextColor(QtGui.QColor(249,168,12))
self.infoText.append("Could not apply updates automatically.")
self.infoText.moveCursor(QtGui.QTextCursor.End)
self.infoText.setTextColor(QtGui.QColor(255,255,255))
#extract all to an Update folder
version = self.checkLatestVersion()
self.infoText.setTextColor(QtGui.QColor(255,255,255))
updateDir = os.path.join(self.toolsPath, "Update_" + str(version))
if not os.path.exists(updateDir):
os.makedirs(updateDir)
self.infoText.append("Extracting updated files to:\n " + str(updateDir))
try:
zf.extractall(updateDir)
except Exception as e:
self.infoText.setTextColor(QtGui.QColor(249,168,12))
self.infoText.append("Operation Failed")
self.infoText.append(str(e))
self.infoText.moveCursor(QtGui.QTextCursor.End)
#report on operation
self.infoText.append("Update Extracted. Since the automatic operation failed, you will need to manually integrate and apply the updates.")
self.infoText.moveCursor(QtGui.QTextCursor.End)
else:
self.infoText.setTextColor(QtGui.QColor(48,255,0))
self.infoText.append("\n\nUpdate Operation Completed!")
self.infoText.append("You must restart Maya to have updates applied.")
self.infoText.moveCursor(QtGui.QTextCursor.End)
#delete zipFile
try:
os.remove(filePath)
for each in os.listdir(os.path.dirname(mayaToolsZip)):
path = os.path.dirname(mayaToolsZip)
path = os.path.join(path, each)
os.remove(path)
os.chmod(os.path.dirname(mayaToolsZip), stat.S_IWRITE)
shutil.rmtree(os.path.dirname(mayaToolsZip))
except Exception as e:
self.infoText.append("Unable to clean up temporary files..")
self.infoText.append(str(e))
value = self.progressBar.value()
self.progressBar.setValue(value + 1)
#update .mod file with latest version #
self.updateLocalVersion()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def cancel(self):
self.close()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def invalidCreds(self):
self.infoText.setTextColor(QtGui.QColor(249,241,12))
self.infoText.append("You have either not setup your Github credentials under Settings, or your github account is not linked with your Epic Games account.")
self.infoText.append("For more information on linking your github and Epic Games accounts, see:\n")
self.infoText.append("https://www.unrealengine.com/ue4-on-github")
self.infoText.setTextColor(QtGui.QColor(255,255,255))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def run():
if cmds.window("pyArtUpdaterWin", exists = True):
cmds.deleteUI("pyArtUpdaterWin", wnd = True)
gui = ART_Updater(getMainWindow())
gui.show()

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Author: Jeremy Ernst
This module has utility functions for dealing with github interactions.
"""
from functools import partial
from ThirdParty.Qt import QtCore, QtWidgets
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def getGitCreds():
"""
Get the github credentials stored in the QSettings
:return: github username and password
"""
settings = QtCore.QSettings("Epic Games", "ARTv2")
user = settings.value("gitUser")
password = settings.value("gitPass")
if user is not None and password is not None:
return [user, password]
else:
return None
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def gitWriteCreds(username, password, ui):
"""
Set the QSettings values for the username and password with the supplied information.
:param username: user-entered github username
:param password: user-entered github password
:param ui: instance of UI where use enters above information
"""
settings = QtCore.QSettings("Epic Games", "ARTv2")
settings.setValue("gitUser", username.text())
settings.setValue("gitPass", password.text())
ui.close()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def gitCredsUI(parent):
"""
Create an interface that allows user to enter github username and password.
:param parent: interface that this interface will be a child of.
"""
credsDialog = QtWidgets.QDialog(parent)
credsDialog.setWindowTitle("Github Credentials")
credsDialog.setMinimumSize(QtCore.QSize(200, 120))
credsDialog.setMaximumSize(QtCore.QSize(200, 120))
layout = QtWidgets.QVBoxLayout(credsDialog)
userName = QtWidgets.QLineEdit()
userName.setPlaceholderText("Github User Name..")
layout.addWidget(userName)
password = QtWidgets.QLineEdit()
password.setPlaceholderText("Github Password..")
layout.addWidget(password)
password.setEchoMode(QtWidgets.QLineEdit.Password)
confirmButton = QtWidgets.QPushButton("Confirm")
layout.addWidget(confirmButton)
confirmButton.setObjectName("blueButton")
confirmButton.clicked.connect(partial(gitWriteCreds, userName, password, credsDialog))
credsDialog.exec_()

View File

@@ -0,0 +1,643 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# standard imports
from __future__ import print_function
import os
from stat import S_IWUSR, S_IREAD
import maya.cmds as cmds
import utils
from ThirdParty.Qt import QtGui, QtCore, QtWidgets, QtCompat
# Use QtCompat from Qt.py for shiboken compatibility
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def getMainWindow():
import maya.OpenMayaUI as mui
pointer = mui.MQtUtil.mainWindow()
# pyside QMainWindow takes in a QWidget rather than QObject
return QtCompat.wrapInstance(int(pointer), QtWidgets.QWidget)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def writeQSS(filePath):
# this function takes the qss file given, and finds and replaces any image path URLs using the user's settings for
# the icons path and changes the file on disk
settings = QtCore.QSettings("Epic Games", "ARTv2")
scriptsPath = settings.value("scriptPath")
scriptsPath = utils.returnFriendlyPath(scriptsPath)
iconPath = settings.value("iconPath")
iconPath = utils.returnFriendlyPath(iconPath)
f = open(filePath, "r")
lines = f.readlines()
f.close()
newLines = []
for line in lines:
if line.find("url(") != -1:
oldPath = line.partition("(")[2].rpartition("/")[0]
replacePath = utils.returnNicePath(iconPath, "System")
newLine = line.replace(oldPath, replacePath)
newLines.append(newLine)
else:
newLines.append(line)
os.chmod(filePath, S_IWUSR | S_IREAD)
f = open(filePath, "w")
for line in newLines:
f.write(line)
f.close()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def addTextToButton(text, parent, centered=True, top=False, bottom=False):
text = QtWidgets.QGraphicsSimpleTextItem(text, parent)
font = QtGui.QFont()
font.setBold(True)
font.setPointSize(12)
text.setFont(font)
textPos = parent.boundingRect().center()
textRect = text.boundingRect()
parentRect = parent.boundingRect()
if centered:
text.setPos(textPos.x() - textRect.width() / 2, textPos.y() - textRect.height() / 2)
if top:
text.setPos(textPos.x() - textRect.width() / 2, textPos.y() - (parentRect.height() / 2 + textRect.height()))
if bottom:
text.setPos(textPos.x() - textRect.width() / 2, textPos.y() + (parentRect.height() / 2))
return text
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class progressDialog(object):
'''
range is a tuple (min,max)
example:
myBar = progressDialog((0,100000), label="Exporting weights")
for i in range(0,100000):
myBar.setValue(i)
'''
def __init__(self, range, label='Doin Stuff..', freq=10):
self.rangeMin, self.rangeMax, self.freq = range[0], range[1], freq
self.bar = QtWidgets.QProgressDialog(label, None, self.rangeMin, self.rangeMax)
self.bar.setWindowModality(QtCore.Qt.WindowModal)
self.bar.autoClose()
def setValue(self, val):
self.bar.show()
QtWidgets.QApplication.processEvents()
if val % self.freq == 0 or (val + 1) == self.rangeMax:
self.bar.setValue(val + 1)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class ProgressBar(QtWidgets.QProgressBar):
def __init__(self, title, parent=None):
super(ProgressBar, self).__init__()
settings = QtCore.QSettings("Epic Games", "ARTv2")
self.toolsPath = settings.value("toolsPath")
# load stylesheet
styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss")
f = open(styleSheetFile, "r")
self.style = f.read()
f.close()
self.setStyleSheet(self.style)
self.setWindowTitle(title)
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowTitleHint | QtCore.Qt.CustomizeWindowHint)
self.setMinimumSize(QtCore.QSize(400, 40))
self.setMaximumSize(QtCore.QSize(400, 40))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class commentBoxItem(QtWidgets.QGraphicsRectItem):
def __init__(self, x, y, w, h, scene, view, animUI):
super(commentBoxItem, self).__init__(x, y, w, h)
self.brush = QtGui.QBrush(QtGui.QColor(60, 60, 60, 125))
self.brushColor = self.brush.color()
self.width = w
self.height = h
self.x = x
self.y = y
self.scale = 1
self.menu = QtWidgets.QMenu()
self.scene = scene
self.view = view
self.animUI = animUI
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges)
# add items to context menu
self.menu.addAction("Change Color", self.changeBoxColor)
self.menu.addAction("Rename", self.changeLabelText)
self.menu.addAction("Remove Comment Box", self.deleteCommentBox)
# add text (Qt5/PySide2 compatible - only takes text and parent)
self.textLabel = QtWidgets.QGraphicsTextItem("Comment Box", self)
self.textLabel.setPos(x, y - 20)
self.textLabel.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
# self.textLabel.setTextInteractionFlags(QtCore.Qt.TextEditable)
self.classType = "comment"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def boundingRect(self):
rect = QtCore.QRectF(self.x, self.y, self.width, self.height)
return rect
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def paint(self, painter, option, widget):
rec = self.boundingRect()
self.blackPen = QtGui.QPen(QtCore.Qt.black)
self.blackPen.setWidth(0)
painter.setPen(self.blackPen)
painter.fillRect(rec, self.brush)
painter.drawRect(rec)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def contextMenuEvent(self, event):
self.menu.exec_(event.screenPos())
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def changeBoxColor(self):
# launch a color dialog to get a new color
newColor = QtGui.QColorDialog.getColor()
newColor.setAlpha(100)
self.brush.setColor(newColor)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def changeLabelText(self):
text = QtWidgets.QInputDialog.getText(self.scene.parent(), "Comment Box", "Enter Label Text:")
if text:
self.textLabel.setPlainText(text[0])
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def deleteCommentBox(self):
self.scene.removeItem(self)
self.animUI.rubberband.hide()
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class pickerBorderItem(QtWidgets.QGraphicsRectItem):
def __init__(self, x, y, w, h, brush, moduleName, niceName=None):
super(pickerBorderItem, self).__init__(x, y, w, h)
self.brush = brush
self.brushColor = brush.color()
self.width = w
self.height = h
self.x = x
self.y = y
self.scale = 1
self.mouseDown = False
self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable)
self.setFlag(QtWidgets.QGraphicsItem.ItemIsFocusable)
self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges)
self.setData(QtCore.Qt.UserRole, moduleName)
self.setData(2, niceName)
self.classType = "border"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def boundingRect(self):
rect = QtCore.QRectF(self.x, self.y, self.width, self.height)
return rect
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def paint(self, painter, option, widget):
rec = self.boundingRect()
blackPen = QtGui.QPen(QtCore.Qt.transparent)
blackPen.setWidth(0)
blackPen.setStyle(QtCore.Qt.DotLine)
painter.setPen(blackPen)
flags = self.flags()
if flags & QtWidgets.QGraphicsItem.ItemIsMovable:
blackPen = QtGui.QPen(QtCore.Qt.black)
blackPen.setWidth(0)
blackPen.setStyle(QtCore.Qt.DotLine)
painter.setPen(blackPen)
if self.isSelected():
blackPen = QtGui.QPen(QtCore.Qt.white)
blackPen.setWidth(0)
blackPen.setStyle(QtCore.Qt.DotLine)
painter.setPen(blackPen)
painter.fillRect(rec, self.brush)
painter.drawRect(rec)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def wheelEvent(self, event):
# only if the focusable flag is set to true, do we continue
flags = self.flags()
if flags & QtWidgets.QGraphicsItem.ItemIsFocusable:
self.scale = self.data(1)
if self.scale is None:
self.scale = 1
scale = float(event.delta() / 8.0)
self.scale = float((scale / 15.0) / 10) + self.scale
self.setData(1, self.scale)
self.setTransformOriginPoint(self.boundingRect().center())
self.setScale(self.scale)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def keyPressEvent(self, event):
self.setTransformOriginPoint(self.boundingRect().center())
if event.key() == QtCore.Qt.Key_Left:
self.setRotation(self.rotation() - 10)
if event.key() == QtCore.Qt.Key_Right:
self.setRotation(self.rotation() + 10)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class pickerButton(QtWidgets.QGraphicsItem):
def __init__(self, width, height, relativePos, controlObj, brush, parent=None):
super(pickerButton, self).__init__(parent)
self.parentItem().setZValue(1)
self.setZValue(2)
self.brush = QtGui.QBrush(brush)
self.brushColor = brush
self.width = width
self.height = height
self.relativePos = relativePos
self.object = controlObj
self.setPos(self.parentItem().boundingRect().topLeft())
self.setPos(self.pos().x() + self.relativePos[0], self.pos().y() + self.relativePos[1])
self.menu = QtWidgets.QMenu()
self.classType = "pickerButton"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def boundingRect(self):
rect = QtCore.QRectF(0, 0, self.width, self.height)
return rect
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def paint(self, painter, option, widget):
rec = self.boundingRect()
painter.fillRect(rec, self.brush)
painter.drawRect(rec)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mousePressEvent(self, event):
mods = cmds.getModifiers()
if (mods & 1) > 0:
cmds.select(self.object, tgl=True)
if (mods & 1) == 0:
cmds.select(self.object)
if self.object in cmds.ls(sl=True):
self.brush.setColor(QtCore.Qt.white)
else:
self.brush.setColor(self.brushColor)
self.update()
QtWidgets.QGraphicsItem.mousePressEvent(self, event)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mousePressEventCustom(self, event):
cmds.select(self.object, tgl=True)
self.brush.setColor(self.brushColor)
self.update()
QtWidgets.QGraphicsItem.mousePressEvent(self, event)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mouseMoveEvent(self, event):
print("mouse move event")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def dragMoveEvent(self, event):
print("drag move event")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def hoverMoveEvent(self, event):
print("hover move event")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def contextMenuEvent(self, event):
self.menu.exec_(event.screenPos())
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class pickerButtonCustom(QtWidgets.QGraphicsPolygonItem):
def __init__(self, width, height, pointArray, relativePos, controlObj, brush, parent=None):
super(pickerButtonCustom, self).__init__(parent)
self.parentItem().setZValue(1)
self.setZValue(2)
self.brush = QtGui.QBrush(brush)
self.brushColor = brush
self.pointArray = pointArray
self.poly = self.createPolygon()
self.setPolygon(self.poly)
# position item
self.relativePos = relativePos
self.object = controlObj
self.setPos(self.parentItem().boundingRect().topLeft())
self.setPos(self.pos().x() + self.relativePos[0], self.pos().y() + self.relativePos[1])
# create menu
self.menu = QtWidgets.QMenu()
self.classType = "pickerButton"
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def createPolygon(self):
polygon = QtGui.QPolygonF()
for each in self.pointArray:
polygon.append(QtCore.QPointF(each[0], each[1]))
return polygon
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def paint(self, painter, option, widget):
painter.setBrush(self.brush)
painter.drawPolygon(self.polygon())
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mousePressEvent(self, event):
mods = cmds.getModifiers()
if (mods & 1) > 0:
cmds.select(self.object, tgl=True)
if (mods & 1) == 0:
cmds.select(self.object)
if self.object in cmds.ls(sl=True):
self.brush.setColor(QtCore.Qt.white)
else:
self.brush.setColor(self.brushColor)
self.update()
QtWidgets.QGraphicsPolygonItem.mousePressEvent(self, event)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mousePressEventCustom(self, event):
cmds.select(self.object, tgl=True)
self.brush.setColor(self.brushColor)
self.update()
QtWidgets.QGraphicsItem.mousePressEvent(self, event)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def contextMenuEvent(self, event):
self.menu.exec_(event.screenPos())
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class pickerButtonAll(QtWidgets.QGraphicsItem):
def __init__(self, width, height, relativePos, controlObjects, brush, parent=None):
super(pickerButtonAll, self).__init__(parent)
self.parentItem().setZValue(1)
self.setZValue(2)
self.brush = QtGui.QBrush(brush)
self.brushColor = brush
self.width = width
self.height = height
self.relativePos = relativePos
self.objects = controlObjects
self.setPos(self.parentItem().boundingRect().topLeft())
self.setPos(self.pos().x() + self.relativePos[0], self.pos().y() + self.relativePos[1])
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def boundingRect(self):
rect = QtCore.QRectF(0, 0, self.width, self.height)
return rect
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def paint(self, painter, option, widget):
rec = self.boundingRect()
painter.fillRect(rec, self.brush)
painter.drawRect(rec)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def mousePressEvent(self, event):
mods = cmds.getModifiers()
if (mods & 1) > 0:
for obj in self.objects:
cmds.select(obj, add=True)
if (mods & 1) == 0:
cmds.select(clear=True)
for obj in self.objects:
cmds.select(obj, tgl=True)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class DialogMessage(QtWidgets.QMainWindow):
def __init__(self, title, message, elementList, elementSize, parent=None):
super(DialogMessage, self).__init__(parent)
# get the directory path of the
settings = QtCore.QSettings("Epic Games", "ARTv2")
self.toolsPath = settings.value("toolsPath")
self.iconsPath = settings.value("iconPath")
# load stylesheet
styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss")
f = open(styleSheetFile, "r")
style = f.read()
f.close()
self.setStyleSheet(style)
# size policies
mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
# create the main widget
self.mainWidget = QtWidgets.QWidget()
self.setCentralWidget(self.mainWidget)
# set qt object name
self.setObjectName("pyART_customDialogMessageWin")
self.setWindowTitle(title)
# create the mainLayout for the rig creator UI
self.mainLayout = QtWidgets.QVBoxLayout(self.mainWidget)
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.resize(300, 200)
self.setSizePolicy(mainSizePolicy)
self.setMinimumSize(QtCore.QSize(300, 200))
self.setMaximumSize(QtCore.QSize(300, 200))
# create the background image
self.frame = QtWidgets.QFrame()
self.mainLayout.addWidget(self.frame)
# create the layout for the widgets
self.widgetLayout = QtWidgets.QVBoxLayout(self.frame)
# add the message to the layout
self.messageArea = QtWidgets.QTextEdit()
self.messageArea.setReadOnly(True)
self.widgetLayout.addWidget(self.messageArea)
self.messageArea.setTextColor(QtGui.QColor(236, 217, 0))
self.messageArea.append(message + "\n\n")
string = ""
for each in elementList:
for i in range(elementSize):
string += each[i] + " "
self.messageArea.setTextColor(QtGui.QColor(255, 255, 255))
self.messageArea.append(string)
# add the OK button
self.confirmButton = QtWidgets.QPushButton("OK")
self.confirmButton.setObjectName("blueButton")
self.widgetLayout.addWidget(self.confirmButton)
self.confirmButton.clicked.connect(self.closeWindow)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def closeWindow(self):
cmds.deleteUI("pyART_customDialogMessageWin", wnd=True)

View File

@@ -0,0 +1,210 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Math utilities
2015, Epic Games
"""
from __future__ import print_function
import math
import maya.api.OpenMaya as om
import maya.cmds as cmds
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CLASSES
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class KDTreeNode():
def __init__(self, point, left, right):
self.point = point
self.left = left
self.right = right
def is_leaf(self):
return (self.left is None and self.right is None)
class KDTreeNeighbours():
""" Internal structure used in nearest-neighbours search.
"""
def __init__(self, query_point, t):
self.query_point = query_point
self.t = t # neighbours wanted
self.largest_distance = 0 # squared
self.current_best = []
def calculate_largest(self):
if self.t >= len(self.current_best):
self.largest_distance = self.current_best[-1][1]
else:
self.largest_distance = self.current_best[self.t - 1][1]
def add(self, point):
sd = square_distance(point, self.query_point)
# run through current_best, try to find appropriate place
for i, e in enumerate(self.current_best):
if i == self.t:
return # enough neighbours, this one is farther, let's forget it
if e[1] > sd:
self.current_best.insert(i, [point, sd])
self.calculate_largest()
return
# append it to the end otherwise
self.current_best.append([point, sd])
self.calculate_largest()
def get_best(self):
return [element[0] for element in self.current_best[:self.t]]
class KDTree():
""" KDTree implementation built from http://en.wikipedia.org/wiki/K-d_tree as a starting point
Example usage:
from kdtree import KDTree
tree = KDTree.construct_from_data(data)
nearest = tree.query(point, t=4) # find nearest 4 points
"""
def __init__(self, data):
def build_kdtree(point_list, depth):
if not point_list:
return None
# check that all points share the same dimensions
dim = len(point_list[0])
for point in point_list:
if len(point) != dim:
print(f'KDTREE: point {point} does not have {dim} dimensions.')
# select axis based on depth modulo tested dimension
axis = depth % dim
# sort point list
point_list.sort(key=lambda point: point[axis])
# choose the median
median = len(point_list) // 2
# create node and recursively construct subtrees
node = KDTreeNode(point=point_list[median],
left=build_kdtree(point_list[0:median], depth + 1),
right=build_kdtree(point_list[median + 1:], depth + 1))
return node
self.root_node = build_kdtree(data, depth=0)
@staticmethod
def construct_from_data(data):
tree = KDTree(data)
return tree
def query(self, query_point, t=1, debug=1):
stats = {'nodes_visited': 0, 'far_search': 0, 'leafs_reached': 0}
def nn_search(node, query_point, t, depth, best_neighbours):
if node is None:
return
stats['nodes_visited'] += 1
# if we have reached a leaf, let's add to current best neighbours,
# (if it's better than the worst one or if there is not enough neighbours)
if node.is_leaf():
# statistics['leafs_reached'] += 1
best_neighbours.add(node.point)
return
# this node is no leaf
# select dimension for comparison (based on current depth)
axis = depth % len(query_point)
# figure out which subtree to search
near_subtree = None # near subtree
far_subtree = None # far subtree (perhaps we'll have to traverse it as well)
# compare query_point and point of current node in selected dimension
# and figure out which subtree is farther than the other
if query_point[axis] < node.point[axis]:
near_subtree = node.left
far_subtree = node.right
else:
near_subtree = node.right
far_subtree = node.left
# recursively search through the tree until a leaf is found
nn_search(near_subtree, query_point, t, depth + 1, best_neighbours)
# while unwinding the recursion, check if the current node
# is closer to query point than the current best,
# also, until t points have been found, search radius is infinity
best_neighbours.add(node.point)
# check whether there could be any points on the other side of the
# splitting plane that are closer to the query point than the current best
if (node.point[axis] - query_point[axis]) ** 2 < best_neighbours.largest_distance:
# statistics['far_search'] += 1
nn_search(far_subtree, query_point, t, depth + 1, best_neighbours)
return
# if there's no tree, there's no neighbors
if self.root_node is not None:
neighbours = KDTreeNeighbours(query_point, t)
nn_search(self.root_node, query_point, t, depth=0, best_neighbours=neighbours)
result = neighbours.get_best()
else:
result = []
# print statistics
return result
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# METHODS
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def square_distance(self, pointA, pointB):
# squared euclidean distance
distance = 0
dimensions = len(pointA) # assumes both points have the same dimensions
for dimension in range(dimensions):
distance += (pointA[dimension] - pointB[dimension]) ** 2
return distance
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def getAngleBetween(object1, object2):
point1 = cmds.xform(object1, t=True, q=True, ws=True)
vector1 = om.MVector(point1)
point2 = cmds.xform(object2, t=True, q=True, ws=True)
vector2 = om.MVector(point2)
dotProduct = vector1.normal() * vector2.normal()
angle = math.acos(dotProduct) * 180 / math.pi
return angle
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def returnPercentile(incomingRange, percent, key=lambda x: x):
floor = math.floor(percent)
ceil = math.ceil(percent)
if percent == 1:
return incomingRange[1]
if percent == 0:
return incomingRange[0]
d0 = key(incomingRange[int(floor)] * (ceil - percent))
d1 = key(incomingRange[int(ceil)] * (percent - floor))
return d0 + d1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff