305 lines
10 KiB
Python
305 lines
10 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from PySide2 import QtWidgets, QtCore, QtGui
|
|
from shiboken2 import wrapInstance
|
|
from maya import OpenMayaUI as omui
|
|
import maya.cmds as cmds
|
|
import maya.mel as mel
|
|
import maya.utils as utils
|
|
import importlib
|
|
import traceback
|
|
import subprocess
|
|
import webbrowser
|
|
import locale
|
|
import sys
|
|
import os
|
|
|
|
# 全局变量声明
|
|
TOOL_PATH = os.path.dirname(os.path.abspath(__file__)).replace('\\', '/')
|
|
TOOL_ICON = os.path.join(TOOL_PATH, "icons", "logo.png")
|
|
if not os.path.exists(TOOL_ICON):
|
|
print(f"Warning: Icon file not found at {TOOL_ICON}")
|
|
TOOL_ICON = "" # 设置为空字符串而不是 None
|
|
MAYA_VERSION = cmds.about(version=True)
|
|
TOOL_NAME = "MetaFusion"
|
|
TOOL_VERSION = "v1.0.0"
|
|
TOOL_AUTHOR = "CGNICO"
|
|
CURRENT_LANG = "en_US"
|
|
WKSP_CTRL = TOOL_NAME
|
|
DNA_PATH = ""
|
|
WKSP_PATH = "MetaFusion"
|
|
HelpURL = f"https://gitea.cgnico.com/CGNICO/{TOOL_NAME}/wiki"
|
|
|
|
#==================================================== GLOBAL FUNCTIONS ====================================================
|
|
class SetButton(QtWidgets.QPushButton):
|
|
"""
|
|
Custom rounded button class
|
|
|
|
Features:
|
|
- Rounded design
|
|
- Custom color and hover effect
|
|
- Bold text
|
|
"""
|
|
def __init__(self, text="", icon=None, color="#D0D0D0", hover_color="#E0E0E0", pressed_color="#C0C0C0"):
|
|
super(SetButton, self).__init__(text)
|
|
if icon:
|
|
self.setIcon(icon)
|
|
self.setIconSize(QtCore.QSize(24, 24))
|
|
self.setMinimumHeight(30) # Set minimum height
|
|
self.setStyleSheet(
|
|
f"""
|
|
QPushButton {{
|
|
background-color: {color};
|
|
color: #303030;
|
|
border-radius: 10px;
|
|
padding: 5px;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
}}
|
|
QPushButton:hover {{
|
|
background-color: {hover_color};
|
|
}}
|
|
QPushButton:pressed {{
|
|
background-color: {pressed_color};
|
|
}}
|
|
"""
|
|
)
|
|
|
|
def get_system_encoding():
|
|
encoding = sys.getdefaultencoding()
|
|
if encoding.lower() == 'ascii':
|
|
encoding = locale.getpreferredencoding()
|
|
return encoding
|
|
|
|
def maya_main_window():
|
|
main_window_ptr = omui.MQtUtil.mainWindow()
|
|
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
|
|
|
|
LANG = {
|
|
'en_US': {
|
|
"Group 01": "Group 01",
|
|
"Group 02": "Group 02",
|
|
"Button 01": "Button 01",
|
|
"Button 02": "Button 02",
|
|
"DOCUMENT": "DOCUMENT",
|
|
"Help": "Help",
|
|
"Switch Language": "Switch Language"
|
|
},
|
|
'zh_CN': {
|
|
"Group 01": "组 01",
|
|
"Group 02": "组 02",
|
|
"Button 01": "按钮 01",
|
|
"Button 02": "按钮 02",
|
|
"DOCUMENT": "文档",
|
|
"Help": "帮助",
|
|
"Switch Language": "切换语言"
|
|
}
|
|
}
|
|
|
|
#==================================================== MAIN WINDOW CLASS ====================================================
|
|
class MainWindow(QtWidgets.QWidget):
|
|
def __init__(self, parent=None):
|
|
super(MainWindow, self).__init__(parent)
|
|
self.setWindowTitle(TOOL_NAME)
|
|
self.setObjectName(TOOL_NAME)
|
|
self.setWindowFlags(QtCore.Qt.Window)
|
|
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
|
self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
|
|
self.setMinimumSize(300, 800)
|
|
self.create_widgets()
|
|
self.create_layouts()
|
|
self.create_connections()
|
|
|
|
if os.path.exists(TOOL_ICON):
|
|
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
|
else:
|
|
print(f"WARNING: Icon file not found: {TOOL_ICON}")
|
|
|
|
#==================================================== UI COMPONENTS ====================================================
|
|
def create_widgets(self):
|
|
|
|
self.group_01 = QtWidgets.QGroupBox(LANG[CURRENT_LANG]["Group 01"])
|
|
self.group_01_button = SetButton(LANG[CURRENT_LANG]["Button 01"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
|
|
self.group_02 = QtWidgets.QGroupBox(LANG[CURRENT_LANG]["Group 02"])
|
|
self.group_02_button = SetButton(LANG[CURRENT_LANG]["Button 02"], color="#FFCCBC", hover_color="#FFAB91", pressed_color="#FF8A65")
|
|
|
|
self.help_btn = QtWidgets.QPushButton(LANG[CURRENT_LANG]["DOCUMENT"])
|
|
self.help_btn.setToolTip(LANG[CURRENT_LANG]["Help"])
|
|
self.help_btn.setFixedSize(100, 20)
|
|
self.help_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: transparent;
|
|
border: none;
|
|
color: gray;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
color: black;
|
|
}
|
|
""")
|
|
self.lang_btn = QtWidgets.QPushButton("EN" if CURRENT_LANG == 'zh_CN' else "ZH")
|
|
self.lang_btn.setToolTip(LANG[CURRENT_LANG]["Switch Language"])
|
|
self.lang_btn.setFixedSize(30, 20)
|
|
self.lang_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: transparent;
|
|
border: none;
|
|
color: gray;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
color: black;
|
|
}
|
|
""")
|
|
|
|
def create_layouts(self):
|
|
main_layout = QtWidgets.QVBoxLayout(self)
|
|
main_layout.setContentsMargins(2, 2, 2, 2)
|
|
main_layout.addStretch()
|
|
main_layout.addWidget(self.group_01)
|
|
main_layout.addWidget(self.group_01_button)
|
|
main_layout.addWidget(self.group_02)
|
|
main_layout.addWidget(self.group_02_button)
|
|
main_layout.addStretch()
|
|
|
|
# Bottom layout
|
|
bottom_layout = QtWidgets.QHBoxLayout()
|
|
icon_label = QtWidgets.QLabel()
|
|
if TOOL_ICON and os.path.exists(TOOL_ICON):
|
|
icon = QtGui.QPixmap(TOOL_ICON).scaled(24, 24, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
|
|
icon_label.setPixmap(icon)
|
|
|
|
bottom_layout.addWidget(icon_label)
|
|
version_label = QtWidgets.QLabel(f"{TOOL_VERSION}")
|
|
version_label.setStyleSheet("color: gray; font-size: 12px;")
|
|
bottom_layout.addWidget(version_label)
|
|
bottom_layout.addStretch()
|
|
bottom_layout.addWidget(self.help_btn)
|
|
bottom_layout.addWidget(self.lang_btn)
|
|
main_layout.addLayout(bottom_layout)
|
|
|
|
def create_connections(self):
|
|
self.group_01_button.clicked.connect(self.run_group_01)
|
|
self.group_02_button.clicked.connect(self.run_group_02)
|
|
self.help_btn.clicked.connect(self.show_help)
|
|
self.lang_btn.clicked.connect(self.switch_language)
|
|
|
|
def run_group_01(self):
|
|
print("Button 01")
|
|
|
|
def run_group_02(self):
|
|
print("Button 02")
|
|
|
|
def dock_to_maya(self):
|
|
if not WKSP_CTRL:
|
|
print("Error: WKSP_CTRL is not defined")
|
|
return
|
|
|
|
if cmds.workspaceControl(WKSP_CTRL, exists=True):
|
|
cmds.deleteUI(WKSP_CTRL)
|
|
|
|
def create_control():
|
|
try:
|
|
if not self.objectName():
|
|
self.setObjectName(TOOL_NAME)
|
|
|
|
workspace_control = cmds.workspaceControl(
|
|
WKSP_CTRL,
|
|
label=TOOL_NAME,
|
|
floating=True,
|
|
retain=False,
|
|
resizeWidth=True,
|
|
initialWidth=300,
|
|
minimumWidth=300
|
|
)
|
|
|
|
if not workspace_control:
|
|
raise RuntimeError("Failed to create workspace control")
|
|
|
|
cmds.workspaceControl(WKSP_CTRL, e=True, resizeWidth=True)
|
|
|
|
try:
|
|
cmds.control(self.objectName(), e=True, p=workspace_control)
|
|
except Exception as e:
|
|
print(f"Error parenting control: {e}")
|
|
return
|
|
|
|
except Exception as e:
|
|
print(f"Error creating workspace control: {e}")
|
|
traceback.print_exc()
|
|
|
|
cmds.evalDeferred(create_control)
|
|
|
|
def show_help(self):
|
|
# Specify the URL of the website you want to open
|
|
webbrowser.open(HelpURL)
|
|
|
|
def switch_language(self):
|
|
global CURRENT_LANG
|
|
CURRENT_LANG = 'en_US' if CURRENT_LANG == 'zh_CN' else 'zh_CN'
|
|
self.lang_btn.setText("EN" if CURRENT_LANG == 'zh_CN' else "CN")
|
|
self.retranslate_ui()
|
|
|
|
QtWidgets.QToolTip.showText(
|
|
self.lang_btn.mapToGlobal(QtCore.QPoint(0, -30)),
|
|
"Language switched" if CURRENT_LANG == 'en_US' else "语言已切换",
|
|
self.lang_btn
|
|
)
|
|
|
|
def show():
|
|
global main_window
|
|
|
|
try:
|
|
current_width = 300
|
|
if cmds.workspaceControl(WKSP_CTRL, exists=True):
|
|
try:
|
|
current_width = cmds.workspaceControl(WKSP_CTRL, q=True, width=True)
|
|
except:
|
|
pass
|
|
cmds.deleteUI(WKSP_CTRL, control=True)
|
|
|
|
if 'main_window' in globals() and main_window:
|
|
try:
|
|
main_window.close()
|
|
main_window.deleteLater()
|
|
except:
|
|
pass
|
|
except Exception as e:
|
|
print(f"Error cleaning up previous window: {e}")
|
|
|
|
def create_ui(retry_count=0, width=300):
|
|
global main_window
|
|
try:
|
|
if not WKSP_CTRL:
|
|
raise ValueError("WKSP_CTRL is not defined")
|
|
|
|
main_window = MainWindow()
|
|
if not main_window:
|
|
raise RuntimeError("Failed to create main window")
|
|
|
|
# 使用 try-except 包装每个 evalDeferred 调用
|
|
def deferred_actions():
|
|
try:
|
|
main_window.dock_to_maya()
|
|
cmds.workspaceControl(WKSP_CTRL, e=True, width=width)
|
|
cmds.workspaceControl(WKSP_CTRL, e=True, resizeWidth=True)
|
|
except Exception as e:
|
|
print(f"Error in deferred actions: {e}")
|
|
|
|
cmds.evalDeferred(deferred_actions)
|
|
|
|
except Exception as e:
|
|
if retry_count < 3:
|
|
print(f"{TOOL_NAME} creation failed, retrying... (Attempt {retry_count + 1})")
|
|
print(f"Error: {str(e)}")
|
|
utils.executeDeferred(lambda: create_ui(retry_count + 1, width))
|
|
else:
|
|
print(f"Failed to create {TOOL_NAME} after 3 attempts:")
|
|
traceback.print_exc()
|
|
|
|
utils.executeDeferred(lambda: create_ui(width=current_width))
|
|
|
|
if __name__ == "__main__":
|
|
show()
|