285 lines
11 KiB
Python
285 lines
11 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Main module for Metahuman customize plugin
|
|
主模块 - 负责初始化UI和功能集成
|
|
功能: 从ui模块加载子模块显示
|
|
作者: Virtuos Games
|
|
版本: Alpha v1.0.0
|
|
"""
|
|
#===================================== IMPORT MODULES =====================================
|
|
from Qt import QtWidgets, QtCore, QtGui
|
|
from Qt.QtCompat import wrapInstance
|
|
from maya import OpenMayaUI as omui
|
|
import maya.cmds as cmds
|
|
import maya.mel as mel
|
|
import maya.utils as utils
|
|
import webbrowser
|
|
import subprocess
|
|
import importlib
|
|
import traceback
|
|
import locale
|
|
import sys
|
|
import os
|
|
#===================================== IMPORT UI MODULES ===================================
|
|
from scripts.ui import toolbar
|
|
from scripts.ui import geometry
|
|
from scripts.ui import rigging
|
|
from scripts.ui import behaviour
|
|
from scripts.ui import definition
|
|
#========================================== CONFIG ========================================
|
|
import config
|
|
TOOL_NAME = config.TOOL_NAME
|
|
TOOL_VERSION = config.TOOL_VERSION
|
|
TOOL_AUTHOR = config.TOOL_AUTHOR
|
|
TOOL_YEAR = config.TOOL_VERSION
|
|
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
|
|
TOOL_LANG = config.TOOL_LANG
|
|
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
|
|
TOOL_HELP_URL = config.TOOL_HELP_URL
|
|
TOOL_PATH = config.TOOL_PATH
|
|
SCRIPTS_PATH = config.SCRIPTS_PATH
|
|
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
|
|
UI_PATH = config.UI_PATH
|
|
STYLE_FILE = config.STYLE_FILE
|
|
ICONS_PATH = config.ICONS_PATH
|
|
TOOL_ICON = config.TOOL_ICON
|
|
ASSETS_PATH = config.ASSETS_PATH
|
|
DNA_FILE_PATH = config.DNA_FILE_PATH
|
|
DNA_IMG_PATH = config.DNA_IMG_PATH
|
|
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
|
#====================================== LOCALIZATION ==================================
|
|
from scripts.ui import localization
|
|
LANG = localization.LANG
|
|
#========================================= INIT =======================================
|
|
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)
|
|
#===================================== MAIN FUNCTION ===================================
|
|
class MainWindow(QtWidgets.QWidget):
|
|
def __init__(self, parent=maya_main_window()):
|
|
super(MainWindow, self).__init__(parent)
|
|
self.setWindowTitle(TOOL_NAME)
|
|
self.setObjectName(f"{TOOL_NAME}MainWindow")
|
|
self.setWindowFlags(QtCore.Qt.Window)
|
|
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
|
|
|
# 设置自适应大小策略
|
|
self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
self.setMinimumSize(300, 600) # 减小最小高度,让窗口更灵活
|
|
|
|
self.create_widgets()
|
|
self.create_layouts()
|
|
self.create_connections()
|
|
if os.path.exists(TOOL_ICON):
|
|
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
|
else:
|
|
print("WARNING: Icon file not found: {}".format(TOOL_ICON))
|
|
|
|
def dock_to_maya(self):
|
|
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
|
|
cmds.deleteUI(TOOL_WSCL_NAME)
|
|
|
|
def create_control():
|
|
try:
|
|
workspace_control = cmds.workspaceControl(
|
|
TOOL_WSCL_NAME,
|
|
label=TOOL_NAME,
|
|
floating=True,
|
|
retain=True,
|
|
resizeWidth=True,
|
|
initialWidth=300,
|
|
minimumWidth=300
|
|
)
|
|
cmds.workspaceControl(TOOL_WSCL_NAME, e=True, resizeWidth=True)
|
|
cmds.control(self.objectName(), e=True, p=workspace_control)
|
|
cmds.evalDeferred(lambda: cmds.workspaceControl(TOOL_WSCL_NAME, e=True, resizeWidth=True))
|
|
except Exception as e:
|
|
print("Error creating workspace control: {}".format(e))
|
|
|
|
cmds.evalDeferred(create_control)
|
|
#===================================== UI COMPONENTS =====================================
|
|
def create_widgets(self):
|
|
# 创建滚动区域
|
|
self.scroll_area = QtWidgets.QScrollArea()
|
|
self.scroll_area.setObjectName("main_scroll_area")
|
|
self.scroll_area.setWidgetResizable(True)
|
|
self.scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
|
self.scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) # 改回按需显示
|
|
self.scroll_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
# 创建滚动区域内容控件
|
|
self.scroll_content = QtWidgets.QWidget()
|
|
self.scroll_content.setObjectName("scroll_content")
|
|
self.scroll_content.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
# 创建主标签页
|
|
self.main_tab = QtWidgets.QTabWidget()
|
|
self.main_tab.setObjectName("main_tab")
|
|
self.main_tab.setTabPosition(QtWidgets.QTabWidget.North)
|
|
self.main_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
|
|
self.main_tab.setDocumentMode(True)
|
|
self.main_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
self.main_tab.setMinimumHeight(400)
|
|
|
|
# 创建各功能模块标签页
|
|
self.geometry_tab = QtWidgets.QWidget()
|
|
self.geometry_tab.setObjectName("geometry_tab")
|
|
self.geometry_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
self.rigging_tab = QtWidgets.QWidget()
|
|
self.rigging_tab.setObjectName("rigging_tab")
|
|
self.rigging_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
self.behaviour_tab = QtWidgets.QWidget()
|
|
self.behaviour_tab.setObjectName("behaviour_tab")
|
|
self.behaviour_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
self.definition_tab = QtWidgets.QWidget()
|
|
self.definition_tab.setObjectName("definition_tab")
|
|
self.definition_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
|
|
|
# 创建工具栏
|
|
self.toolbar_frame = QtWidgets.QFrame()
|
|
self.toolbar_frame.setObjectName("toolbar_frame")
|
|
self.toolbar_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
|
self.toolbar_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
|
self.toolbar_frame.setMaximumHeight(40)
|
|
self.toolbar_frame.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
|
|
|
# 创建状态栏
|
|
self.status_bar = QtWidgets.QStatusBar()
|
|
self.status_bar.setObjectName("status_bar")
|
|
self.status_bar.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
|
self.status_bar.showMessage(f"{TOOL_NAME} {TOOL_VERSION}")
|
|
|
|
# 初始化各模块UI组件
|
|
toolbar.widgets()
|
|
geometry.widgets()
|
|
rigging.widgets()
|
|
behaviour.widgets()
|
|
definition.widgets()
|
|
|
|
def create_layouts(self):
|
|
# 主布局
|
|
self.main_layout = QtWidgets.QVBoxLayout(self)
|
|
self.main_layout.setContentsMargins(2, 2, 2, 2)
|
|
self.main_layout.setSpacing(2)
|
|
|
|
# 滚动区域内容布局
|
|
self.scroll_content_layout = QtWidgets.QVBoxLayout(self.scroll_content)
|
|
self.scroll_content_layout.setContentsMargins(2, 2, 2, 2)
|
|
self.scroll_content_layout.setSpacing(2)
|
|
|
|
# 添加工具栏
|
|
self.toolbar_layout = QtWidgets.QVBoxLayout(self.toolbar_frame)
|
|
self.toolbar_layout.setContentsMargins(0, 0, 0, 0)
|
|
toolbar.layouts(parent_frame=self.toolbar_frame)
|
|
|
|
# 设置各标签页布局
|
|
self.geometry_layout = QtWidgets.QVBoxLayout(self.geometry_tab)
|
|
self.geometry_layout.setContentsMargins(4, 4, 4, 4)
|
|
geometry.layouts(parent_tab=self.geometry_tab)
|
|
|
|
self.rigging_layout = QtWidgets.QVBoxLayout(self.rigging_tab)
|
|
self.rigging_layout.setContentsMargins(4, 4, 4, 4)
|
|
rigging.layouts(parent_tab=self.rigging_tab)
|
|
|
|
self.behaviour_layout = QtWidgets.QVBoxLayout(self.behaviour_tab)
|
|
self.behaviour_layout.setContentsMargins(4, 4, 4, 4)
|
|
behaviour.layouts(parent_tab=self.behaviour_tab)
|
|
|
|
self.definition_layout = QtWidgets.QVBoxLayout(self.definition_tab)
|
|
self.definition_layout.setContentsMargins(4, 4, 4, 4)
|
|
definition.layouts(parent_tab=self.definition_tab)
|
|
|
|
# 添加标签页到主标签控件
|
|
self.main_tab.addTab(self.geometry_tab, "几何模型")
|
|
self.main_tab.addTab(self.rigging_tab, "绑定系统")
|
|
self.main_tab.addTab(self.behaviour_tab, "行为系统")
|
|
self.main_tab.addTab(self.definition_tab, "定义系统")
|
|
|
|
# 将组件添加到滚动区域内容布局
|
|
self.scroll_content_layout.addWidget(self.toolbar_frame)
|
|
self.scroll_content_layout.addWidget(self.main_tab)
|
|
|
|
# 设置滚动区域的内容控件
|
|
self.scroll_area.setWidget(self.scroll_content)
|
|
|
|
# 将滚动区域和状态栏添加到主布局
|
|
self.main_layout.addWidget(self.scroll_area)
|
|
self.main_layout.addWidget(self.status_bar)
|
|
|
|
# 加载样式表
|
|
if os.path.exists(STYLE_FILE):
|
|
try:
|
|
with open(STYLE_FILE, "r", encoding="utf-8") as f:
|
|
style = f.read()
|
|
self.setStyleSheet(style)
|
|
except UnicodeDecodeError:
|
|
# 尝试使用系统默认编码
|
|
encoding = get_system_encoding()
|
|
try:
|
|
with open(STYLE_FILE, "r", encoding=encoding) as f:
|
|
style = f.read()
|
|
self.setStyleSheet(style)
|
|
except Exception as e:
|
|
print(f"警告: 无法加载样式表文件: {e}")
|
|
else:
|
|
print(f"警告: 样式表文件不存在: {STYLE_FILE}")
|
|
|
|
def create_connections(self):
|
|
# 连接各模块的信号和槽
|
|
toolbar.connections()
|
|
geometry.connections()
|
|
rigging.connections()
|
|
behaviour.connections()
|
|
definition.connections()
|
|
|
|
# 标签页切换信号
|
|
self.main_tab.currentChanged.connect(self.on_tab_changed)
|
|
|
|
def on_tab_changed(self, index):
|
|
tab_name = self.main_tab.tabText(index)
|
|
self.status_bar.showMessage(f"当前模块: {tab_name}")
|
|
print(f"切换到模块: {tab_name}")
|
|
|
|
def main():
|
|
"""
|
|
Main function to initialize and show the Plugin UI
|
|
"""
|
|
try:
|
|
# Initialize UI modules with placeholder functions
|
|
# Each module only contains UI framework without actual functionality
|
|
toolbar.toolbar_temp_function()
|
|
geometry.geometry_temp_function()
|
|
rigging.rigging_temp_function()
|
|
behaviour.behaviour_temp_function()
|
|
definition.definition_temp_function()
|
|
|
|
# Create and show main window
|
|
global tool_window
|
|
tool_window = MainWindow()
|
|
tool_window.dock_to_maya()
|
|
|
|
print(f"{TOOL_NAME} plugin initialized successfully!")
|
|
return tool_window
|
|
except Exception as e:
|
|
error_msg = f"Error initializing {TOOL_NAME} plugin: {str(e)}"
|
|
print(error_msg)
|
|
traceback.print_exc()
|
|
cmds.warning(error_msg)
|
|
return None
|
|
|
|
|
|
# Auto-run when imported
|
|
if __name__ == "__main__":
|
|
main()
|