#!/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()