302 lines
12 KiB
Python
302 lines
12 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Main module for Metahuman customize plugin
|
||
主模块 - 负责初始化UI和功能集成
|
||
功能: 从ui模块加载子模块显示
|
||
作者: CGNICO
|
||
版本: 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 ui_utils
|
||
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
|
||
#========================================= LOCALIZATION =====================================
|
||
from scripts.ui import localization
|
||
LANG = localization.LANG
|
||
#=========================================== CONFIG =========================================
|
||
import config
|
||
TOOL_NAME = config.TOOL_NAME
|
||
TOOL_VERSION = config.TOOL_VERSION
|
||
TOOL_AUTHOR = config.TOOL_AUTHOR
|
||
TOOL_YEAR = config.TOOL_YEAR
|
||
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
|
||
TOOL_WIDTH = config.TOOL_WIDTH
|
||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||
#======================================= MAIN FUNCTION =====================================
|
||
class MainWindow(QtWidgets.QWidget):
|
||
def __init__(self, parent=ui_utils.get_maya_main_window()):
|
||
super(MainWindow, self).__init__(parent)
|
||
self.setWindowTitle(TOOL_NAME)
|
||
self.setObjectName(f"{TOOL_NAME}MainWindow")
|
||
self.setMinimumSize(TOOL_WIDTH, TOOL_HEIGHT)
|
||
self.setStyleSheet("")
|
||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||
|
||
# 设置窗口为独立窗口
|
||
self.setWindowFlags(QtCore.Qt.Window)
|
||
|
||
# 设置窗口位置为屏幕中央
|
||
self.center_window()
|
||
|
||
# 设置窗口图标
|
||
if os.path.exists(TOOL_ICON):
|
||
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
||
|
||
# 加载样式表
|
||
self.load_stylesheet()
|
||
|
||
# 初始化UI模块
|
||
self.toolbar_ui = toolbar.ToolbarUI()
|
||
self.definition_ui = definition.DefinitionUI()
|
||
self.geometry_ui = geometry.GeometryUI()
|
||
self.rigging_ui = rigging.RiggingUI()
|
||
self.behaviour_ui = behaviour.BehaviourUI()
|
||
|
||
# 初始化UI组件
|
||
self.create_widgets()
|
||
self.create_layouts()
|
||
self.create_connections()
|
||
|
||
def load_stylesheet(self):
|
||
"""加载样式表"""
|
||
if os.path.exists(STYLE_FILE):
|
||
try:
|
||
with open(STYLE_FILE, 'r', encoding='utf-8') as f:
|
||
style = f.read()
|
||
self.setStyleSheet(style)
|
||
print(f"样式表已加载: {STYLE_FILE}")
|
||
except Exception as e:
|
||
print(f"加载样式表失败: {e}")
|
||
else:
|
||
print(f"样式表文件不存在: {STYLE_FILE}")
|
||
|
||
#========================================= WIDGET =======================================
|
||
def create_widgets(self):
|
||
"""创建UI控件"""
|
||
# 创建工具栏区域
|
||
self.toolbar_widget = QtWidgets.QWidget()
|
||
self.toolbar_widget.setObjectName("toolbarWidget")
|
||
self.toolbar_widget.setMaximumHeight(80) # 限制工具栏高度
|
||
|
||
# 创建功能区域切换按钮组
|
||
self.function_buttons = {}
|
||
self.function_buttons["geometry"] = QtWidgets.QPushButton(LANG.get("geometry", "几何体"))
|
||
self.function_buttons["rigging"] = QtWidgets.QPushButton(LANG.get("rigging", "绑定"))
|
||
self.function_buttons["behaviour"] = QtWidgets.QPushButton(LANG.get("behaviour", "行为"))
|
||
self.function_buttons["definition"] = QtWidgets.QPushButton(LANG.get("definition", "定义"))
|
||
|
||
# 设置按钮样式和属性
|
||
for key, button in self.function_buttons.items():
|
||
button.setObjectName(f"{key}Button")
|
||
button.setCheckable(True)
|
||
button.setMinimumHeight(40)
|
||
|
||
# 默认选中几何体按钮
|
||
self.function_buttons["geometry"].setChecked(True)
|
||
|
||
# 创建功能面板堆栈
|
||
self.function_stack = QtWidgets.QStackedWidget()
|
||
self.function_stack.setObjectName("functionStack")
|
||
|
||
# 创建各个功能面板
|
||
self.geometry_panel = QtWidgets.QWidget()
|
||
self.rigging_panel = QtWidgets.QWidget()
|
||
self.behaviour_panel = QtWidgets.QWidget()
|
||
self.definition_panel = QtWidgets.QWidget()
|
||
|
||
# 将功能面板添加到堆栈中
|
||
self.function_stack.addWidget(self.geometry_panel)
|
||
self.function_stack.addWidget(self.rigging_panel)
|
||
self.function_stack.addWidget(self.behaviour_panel)
|
||
self.function_stack.addWidget(self.definition_panel)
|
||
|
||
#========================================= LAYOUT =======================================
|
||
def create_layouts(self):
|
||
"""创建布局"""
|
||
# 主布局
|
||
main_layout = QtWidgets.QVBoxLayout(self)
|
||
main_layout.setContentsMargins(2, 2, 2, 2)
|
||
main_layout.setSpacing(2)
|
||
|
||
# 创建工具栏布局
|
||
toolbar_layout = QtWidgets.QHBoxLayout(self.toolbar_widget)
|
||
toolbar_layout.setContentsMargins(5, 5, 5, 5)
|
||
toolbar_layout.setSpacing(5)
|
||
|
||
# 将工具栏UI添加到工具栏布局
|
||
if hasattr(self.toolbar_ui, 'main_widget'):
|
||
toolbar_layout.addWidget(self.toolbar_ui.main_widget)
|
||
|
||
# 创建功能按钮布局
|
||
function_buttons_layout = QtWidgets.QHBoxLayout()
|
||
function_buttons_layout.setContentsMargins(0, 0, 0, 0)
|
||
function_buttons_layout.setSpacing(2)
|
||
|
||
# 添加功能按钮
|
||
for key, button in self.function_buttons.items():
|
||
function_buttons_layout.addWidget(button)
|
||
|
||
# 创建各功能面板的布局
|
||
definition_layout = QtWidgets.QVBoxLayout(self.definition_panel)
|
||
definition_layout.setContentsMargins(0, 0, 0, 0)
|
||
definition_layout.setSpacing(0)
|
||
|
||
geometry_layout = QtWidgets.QVBoxLayout(self.geometry_panel)
|
||
geometry_layout.setContentsMargins(0, 0, 0, 0)
|
||
geometry_layout.setSpacing(0)
|
||
|
||
rigging_layout = QtWidgets.QVBoxLayout(self.rigging_panel)
|
||
rigging_layout.setContentsMargins(0, 0, 0, 0)
|
||
rigging_layout.setSpacing(0)
|
||
|
||
behaviour_layout = QtWidgets.QVBoxLayout(self.behaviour_panel)
|
||
behaviour_layout.setContentsMargins(0, 0, 0, 0)
|
||
behaviour_layout.setSpacing(0)
|
||
|
||
# 将各UI模块添加到对应的功能面板布局中
|
||
if hasattr(self.definition_ui, 'main_widget'):
|
||
definition_layout.addWidget(self.definition_ui.main_widget)
|
||
|
||
if hasattr(self.geometry_ui, 'main_widget'):
|
||
geometry_layout.addWidget(self.geometry_ui.main_widget)
|
||
|
||
# 绑定UI
|
||
if hasattr(self.rigging_ui, 'main_widget'):
|
||
rigging_layout.addWidget(self.rigging_ui.main_widget)
|
||
|
||
# 行为UI
|
||
if hasattr(self.behaviour_ui, 'main_widget'):
|
||
behaviour_layout.addWidget(self.behaviour_ui.main_widget)
|
||
|
||
# 将各组件添加到主布局
|
||
main_layout.addWidget(self.toolbar_widget)
|
||
main_layout.addLayout(function_buttons_layout)
|
||
main_layout.addWidget(self.function_stack, 1) # 给功能面板堆栈设置伸缩因子,使其占据剩余空间
|
||
|
||
#======================================= CONNECTION =====================================
|
||
def create_connections(self):
|
||
"""连接信号和槽"""
|
||
# 功能按钮点击信号
|
||
self.function_buttons["geometry"].clicked.connect(lambda: self.switch_function_panel(0))
|
||
self.function_buttons["rigging"].clicked.connect(lambda: self.switch_function_panel(1))
|
||
self.function_buttons["behaviour"].clicked.connect(lambda: self.switch_function_panel(2))
|
||
self.function_buttons["definition"].clicked.connect(lambda: self.switch_function_panel(3))
|
||
|
||
def switch_function_panel(self, index):
|
||
"""切换功能面板"""
|
||
# 切换堆栈页面
|
||
self.function_stack.setCurrentIndex(index)
|
||
|
||
# 更新按钮状态
|
||
for i, (key, button) in enumerate(self.function_buttons.items()):
|
||
button.setChecked(i == index)
|
||
|
||
# 调整分割器宽度
|
||
self.reset_splitters()
|
||
|
||
# 打印当前面板信息
|
||
panel_names = ["几何体", "绑定", "行为", "定义"]
|
||
print(f"切换到功能面板: {panel_names[index]}")
|
||
|
||
def reset_splitters(self):
|
||
"""重置所有分割器的宽度,确保左右栏宽度均等"""
|
||
# 重置定义面板分割器
|
||
if hasattr(self.definition_ui, 'reset_splitter_sizes'):
|
||
self.definition_ui.reset_splitter_sizes()
|
||
|
||
# 重置行为面板分割器
|
||
if hasattr(self.behaviour_ui, 'reset_splitter_sizes'):
|
||
self.behaviour_ui.reset_splitter_sizes()
|
||
|
||
# 重置绑定面板分割器
|
||
if hasattr(self.rigging_ui, 'reset_splitter_sizes'):
|
||
self.rigging_ui.reset_splitter_sizes()
|
||
|
||
# 重置几何面板分割器
|
||
if hasattr(self.geometry_ui, 'reset_splitter_sizes'):
|
||
self.geometry_ui.reset_splitter_sizes()
|
||
|
||
def center_window(self):
|
||
"""将窗口居中显示在屏幕上"""
|
||
# 获取屏幕几何信息 - 兼容PySide2和PySide6
|
||
try:
|
||
# 使用Qt.py兼容层方式获取屏幕信息
|
||
app = QtWidgets.QApplication.instance()
|
||
screen = app.primaryScreen() if hasattr(app, 'primaryScreen') else None
|
||
if screen:
|
||
screen_rect = screen.availableGeometry()
|
||
else:
|
||
# 尝试使用desktop方法(PySide2兼容)
|
||
if hasattr(QtWidgets.QApplication, 'desktop'):
|
||
desktop = QtWidgets.QApplication.desktop()
|
||
screen_rect = desktop.availableGeometry(desktop.primaryScreen())
|
||
else:
|
||
# 如果都失败,使用默认值
|
||
screen_rect = QtCore.QRect(0, 0, 1920, 1080)
|
||
except Exception as e:
|
||
print(f"获取屏幕信息时出错: {str(e)}")
|
||
# 使用默认值
|
||
screen_rect = QtCore.QRect(0, 0, 1920, 1080)
|
||
|
||
# 计算窗口居中位置
|
||
window_rect = self.frameGeometry()
|
||
center_point = screen_rect.center()
|
||
window_rect.moveCenter(center_point)
|
||
|
||
# 移动窗口到居中位置
|
||
self.move(window_rect.topLeft())
|
||
|
||
def main():
|
||
"""主函数,创建并显示主窗口"""
|
||
try:
|
||
# 如果已存在窗口,则关闭
|
||
for widget in QtWidgets.QApplication.allWidgets():
|
||
if widget.objectName() == f"{TOOL_NAME}MainWindow" and isinstance(widget, QtWidgets.QWidget):
|
||
widget.close()
|
||
widget.deleteLater()
|
||
|
||
# 创建新窗口
|
||
window = MainWindow()
|
||
window.show()
|
||
return window
|
||
except Exception as e:
|
||
error_msg = traceback.format_exc()
|
||
print(f"启动失败: {e}\n{error_msg}")
|
||
return None
|
||
|
||
if __name__ == "__main__":
|
||
main()
|