This commit is contained in:
2025-05-05 18:15:02 +08:00
parent 01c0ec760f
commit 46d93efb3c
11 changed files with 1728 additions and 1943 deletions

View File

@@ -5,7 +5,7 @@
Main module for Metahuman customize plugin
主模块 - 负责初始化UI和功能集成
功能: 从ui模块加载子模块显示
作者: Virtuos Games
作者: CGNICO
版本: Alpha v1.0.0
"""
#===================================== IMPORT MODULES =====================================
@@ -23,261 +23,194 @@ 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 ==================================
#========================================= LOCALIZATION =====================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== CONFIG ========================================
# 从 scripts 模块导入配置变量
from scripts import (
TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_YEAR, TOOL_MOD_FILENAME,
TOOL_LANG, TOOL_WSCL_NAME, TOOL_HELP_URL, TOOL_PATH, SCRIPTS_PATH,
TOOL_MAIN_SCRIPT, UI_PATH, STYLE_FILE, ICONS_PATH, TOOL_ICON,
ASSETS_PATH, DNA_FILE_PATH, DNA_IMG_PATH, TOOL_COMMAND_ICON
)
#========================================= 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 ===================================
#=========================================== 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
#======================================= MAIN FUNCTION =====================================
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=maya_main_window()):
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.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setMinimumSize(1200, 800)
# 设置自适应大小策略
self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.setMinimumSize(300, 600) # 减小最小高度,让窗口更灵活
# 设置窗口图标
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 dock_to_maya(self):
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
cmds.deleteUI(TOOL_WSCL_NAME)
def create_control():
try:
# 直接使用TOOL_ICON__init__.py中已经检查了图标文件是否存在
workspace_control = cmds.workspaceControl(
TOOL_WSCL_NAME,
label=TOOL_NAME,
floating=True,
retain=True,
resizeWidth=True,
initialWidth=600,
minimumWidth=600
)
cmds.workspaceControl(TOOL_WSCL_NAME, e=True, resizeWidth=True)
cmds.control(self.objectName(), e=True, p=workspace_control)
# 尝试设置工作区控件的尺寸和属性
try:
# 使用Maya命令设置工作区控件属性
cmds.workspaceControl(TOOL_WSCL_NAME, e=True, widthProperty="preferred", heightProperty="preferred")
# 使用原始标题,不添加额外的图标字符
cmds.workspaceControl(TOOL_WSCL_NAME, e=True, label=TOOL_NAME)
except Exception as e:
print(f"设置工作区控件属性失败: {e}")
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模块创建工具栏元素
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)
# 加载样式表
def load_stylesheet(self):
"""加载样式表"""
if os.path.exists(STYLE_FILE):
try:
with open(STYLE_FILE, "r", encoding="utf-8") as f:
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}")
print(f"样式表已加载: {STYLE_FILE}")
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()
print(f"样式表文件不存在: {STYLE_FILE}")
#========================================= WIDGET =======================================
def create_widgets(self):
"""创建UI控件"""
# 主标签页控件
self.main_tab_widget = QtWidgets.QTabWidget()
self.main_tab_widget.setObjectName("mainTabWidget")
# 创建各个标签页
self.toolbar_tab = QtWidgets.QWidget()
self.definition_tab = QtWidgets.QWidget()
self.geometry_tab = QtWidgets.QWidget()
self.rigging_tab = QtWidgets.QWidget()
self.behaviour_tab = QtWidgets.QWidget()
# 设置标签页名称
self.main_tab_widget.addTab(self.toolbar_tab, LANG.get("toolbar", "工具栏"))
self.main_tab_widget.addTab(self.definition_tab, LANG.get("definition", "定义"))
self.main_tab_widget.addTab(self.geometry_tab, LANG.get("geometry", "几何体"))
self.main_tab_widget.addTab(self.rigging_tab, LANG.get("rigging", "绑定"))
self.main_tab_widget.addTab(self.behaviour_tab, LANG.get("behaviour", "行为"))
#========================================= LAYOUT =======================================
def create_layouts(self):
"""创建布局"""
# 主布局
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(5, 5, 5, 5)
main_layout.setSpacing(5)
main_layout.addWidget(self.main_tab_widget)
# 设置各标签页的布局
toolbar_layout = QtWidgets.QVBoxLayout(self.toolbar_tab)
definition_layout = QtWidgets.QVBoxLayout(self.definition_tab)
geometry_layout = QtWidgets.QVBoxLayout(self.geometry_tab)
rigging_layout = QtWidgets.QVBoxLayout(self.rigging_tab)
behaviour_layout = QtWidgets.QVBoxLayout(self.behaviour_tab)
# 将各UI模块添加到对应的标签页布局中
# 工具栏UI
if hasattr(self.toolbar_ui, 'main_widget'):
toolbar_layout.addWidget(self.toolbar_ui.main_widget)
# 定义UI
if hasattr(self.definition_ui, 'main_widget'):
definition_layout.addWidget(self.definition_ui.main_widget)
# 几何体UI
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)
#======================================= CONNECTION =====================================
def create_connections(self):
"""连接信号和槽"""
# 标签页切换信号
self.main_tab.currentChanged.connect(self.on_tab_changed)
self.main_tab_widget.currentChanged.connect(self.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 tab_changed(self, index):
"""标签页切换事件处理"""
tab_name = self.main_tab_widget.tabText(index)
print(f"切换到标签页: {tab_name}")
# 调整分割器宽度
self.reset_splitters()
def reset_splitters(self):
"""重置所有分割器的宽度,确保左右栏宽度均等"""
# 延迟执行确保UI完全加载
QtCore.QTimer.singleShot(50, self._do_reset_splitters)
QtCore.QTimer.singleShot(200, self._do_reset_splitters)
def _do_reset_splitters(self):
"""实际执行分割器宽度重置的函数"""
current_tab = self.main_tab_widget.currentWidget()
if not current_tab:
return
# 查找当前标签页中的所有水平分割器
splitters = current_tab.findChildren(QtWidgets.QSplitter)
for splitter in splitters:
if splitter.orientation() == QtCore.Qt.Horizontal:
# 获取分割器宽度
width = splitter.width()
# 计算每个部分应该的宽度
count = splitter.count()
if count > 0:
part_width = width // count
sizes = [part_width] * count
# 设置分割器各部分的宽度
splitter.setSizes(sizes)
# 为每个子项设置相同的伸缩因子
for i in range(count):
splitter.setStretchFactor(i, 1)
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()
# 如果已存在窗口,则关闭
for widget in QtWidgets.QApplication.allWidgets():
if widget.objectName() == f"{TOOL_NAME}MainWindow" and isinstance(widget, QtWidgets.QWidget):
widget.close()
widget.deleteLater()
# 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
# 创建新窗口
window = MainWindow()
window.show()
return 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)
error_msg = traceback.format_exc()
print(f"启动失败: {e}\n{error_msg}")
return None
# Auto-run when imported
if __name__ == "__main__":
main()

View File

@@ -1,43 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
MetaHuman DNA工具包
这个包包含了用于处理MetaHuman DNA文件的工具和实用程序。
"""
import os
import sys
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
DEFAULT_ICON = os.path.join(ICONS_PATH, "commandButton.png").replace("\\", "/")
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
# 确保项目路径在sys.path中
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
# 确保scripts路径在sys.path中
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
from . import *

View File

@@ -4,6 +4,7 @@
"""
Behaviour UI Module for Plugin
行为系统UI模块 - 负责显示角色行为编辑界面和基础操作
基本功能:
- Blendshape自动加载刷新筛选
- 次级Blendshape自动加载刷新筛选
@@ -11,530 +12,249 @@ Behaviour UI Module for Plugin
- Blendshape范围编辑
- Blendshape镜像
- Blendshape查找翻转目标
- Blendshape重建
- 表情控制器还原默认表情
- 查找选择表情
- 控制面板查找
- 选择关联关节
- 写入当前表情
- 写入镜像表情
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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 FUNCTIONS ===================================
from scripts.utils import utils_behaviour as utils_behaviour
from scripts.ui import ui_utils
from scripts.utils import utils_behaviour
#========================================== 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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
blendshape_tree = None
sub_blendshape_tree = None
blendshape_slider = None
blendshape_preview = None
search_input = None
weight_value = None
right_slider = None
right_value = None
restore_button = None
combo_select_button = None
single_target_button = None
combo_target_button = None
batch_target_button = None
add_target_button = None
remove_target_button = None
mirror_target_button = None
flip_target_button = None
plus_button = None
all_button = None
number_buttons_layout = None
# 全局布局变量
search_layout = None
left_bottom_buttons = None
left_slider_layout = None
left_bottom_layout = None
right_slider_layout = None
right_buttons_row1 = None
right_buttons_row2 = None
right_buttons_row3 = None
tab_buttons = None
bottom_slider_layout = None
bottom_slider = None
bottom_value = None
bottom_buttons_row1 = None
bottom_buttons_row2 = None
behaviour_buttons = {}
def set_button_icon(button, icon_name):
class BehaviourUI(ui_utils.BaseUI):
"""
设置按钮图标使用Maya默认图标
Args:
button: 要设置图标的按钮
icon_name: 图标文件名
行为系统UI类 - 负责显示角色行为编辑界面和基础操作
继承自BaseUI类实现行为系统相关的UI功能
"""
# 使用Maya内置图标
from maya import cmds
# 设置按钮图标使用Maya的图标
button.setIcon(QtGui.QIcon(":/{}".format(icon_name)))
button.setIconSize(QtCore.QSize(24, 24)) # 图标尺寸
print(f"成功设置按钮图标: {icon_name}")
# 注意:如果图标加载失败,我们会看到一个空图标,但不会引起错误
#========================================== INIT ========================================
def __init__(self):
"""
初始化行为系统UI
创建主控件和布局,并连接信号和槽
"""
super(BehaviourUI, self).__init__()
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("behaviourMainWidget")
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
def widgets():
"""
创建行为系统UI控件
"""
global blendshape_tree, sub_blendshape_tree, blendshape_slider, blendshape_preview, behaviour_buttons
global search_input, weight_value, right_slider, right_value, restore_button, combo_select_button
global single_target_button, combo_target_button, batch_target_button, add_target_button
global remove_target_button, mirror_target_button, flip_target_button, plus_button, all_button
global number_buttons_layout
# 全局布局变量
global search_layout, left_bottom_buttons, left_slider_layout, left_bottom_layout
global right_slider_layout, right_buttons_row1, right_buttons_row2, right_buttons_row3
global tab_buttons, bottom_slider_layout, bottom_slider, bottom_value
global bottom_buttons_row1, bottom_buttons_row2
# 创建搜索框
search_layout = QtWidgets.QHBoxLayout()
search_icon = QtWidgets.QLabel()
search_icon.setPixmap(QtGui.QIcon(":/magnifyGlass.png").pixmap(16, 16))
search_input = QtWidgets.QLineEdit()
search_input.setPlaceholderText("搜索...")
search_input.setObjectName("SearchInput")
# 主表情控制列表
blendshape_tree = QtWidgets.QListWidget()
blendshape_tree.setObjectName("RawControlList")
blendshape_tree.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
# 相关混合变形列表
sub_blendshape_tree = QtWidgets.QListWidget()
sub_blendshape_tree.setObjectName("RelatedBlendShapesList")
sub_blendshape_tree.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
# 创建权重滑块和数值显示
blendshape_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
blendshape_slider.setMinimum(0)
blendshape_slider.setMaximum(1000) # 使用更精细的值对应到0-1.0
blendshape_slider.setValue(0)
blendshape_slider.setObjectName("WeightSlider")
# 权重数值显示
weight_value = QtWidgets.QLineEdit("0.000")
weight_value.setFixedWidth(50)
weight_value.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
weight_value.setObjectName("WeightValue")
# 全部按钮
all_button = QtWidgets.QPushButton("全部")
all_button.setFixedWidth(60)
all_button.setObjectName("AllButton")
# 数字按钮组
number_buttons_layout = QtWidgets.QHBoxLayout()
for i in range(1, 7): # 1-6的数字按钮
num_button = QtWidgets.QPushButton(str(i))
num_button.setFixedWidth(30)
num_button.setObjectName(f"NumButton{i}")
number_buttons_layout.addWidget(num_button)
# 创建左侧底部按钮
restore_button = QtWidgets.QPushButton("恢复表情")
set_button_icon(restore_button, "undo.png")
restore_button.setObjectName("RestoreButton")
combo_select_button = QtWidgets.QPushButton("组合选择")
set_button_icon(combo_select_button, "selectByHull.png")
combo_select_button.setObjectName("ComboSelectButton")
# 创建右侧按钮
# 第一行按钮
single_target_button = QtWidgets.QPushButton("单个目标表情")
set_button_icon(single_target_button, "blendShape.png")
single_target_button.setObjectName("SingleTargetButton")
combo_target_button = QtWidgets.QPushButton("复合目标表情")
set_button_icon(combo_target_button, "blendShapeEditor.png")
combo_target_button.setObjectName("ComboTargetButton")
batch_target_button = QtWidgets.QPushButton("批量目标表情")
set_button_icon(batch_target_button, "blendShapePanel.png")
batch_target_button.setObjectName("BatchTargetButton")
# 第二行按钮
add_target_button = QtWidgets.QPushButton("添加目标表情")
set_button_icon(add_target_button, "addClip.png")
add_target_button.setObjectName("AddTargetButton")
remove_target_button = QtWidgets.QPushButton("移除目标表情")
set_button_icon(remove_target_button, "removeClip.png")
remove_target_button.setObjectName("RemoveTargetButton")
# 第三行按钮
mirror_target_button = QtWidgets.QPushButton("镜像目标表情")
set_button_icon(mirror_target_button, "mirrorJoint.png")
mirror_target_button.setObjectName("MirrorTargetButton")
flip_target_button = QtWidgets.QPushButton("翻转目标表情")
set_button_icon(flip_target_button, "flipTriangle.png")
flip_target_button.setObjectName("FlipTargetButton")
# 右侧滑块和数值显示
right_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
right_slider.setMinimum(0)
right_slider.setMaximum(1000) # 使用更精细的值对应到0-1.0
right_slider.setValue(0)
right_slider.setObjectName("RightSlider")
right_value = QtWidgets.QLineEdit("0.000")
right_value.setFixedWidth(50)
right_value.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
right_value.setObjectName("RightValue")
# 添加加号按钮
plus_button = QtWidgets.QPushButton("+")
plus_button.setFixedSize(30, 30)
plus_button.setObjectName("PlusButton")
# 底部按钮
# 第一行按钮
behaviour_buttons["reset_controller"] = QtWidgets.QPushButton("还原默认表情")
set_button_icon(behaviour_buttons["reset_controller"], "undo.png")
behaviour_buttons["find_expression"] = QtWidgets.QPushButton("查找选择表情")
set_button_icon(behaviour_buttons["find_expression"], "find.png")
behaviour_buttons["find_control_panel"] = QtWidgets.QPushButton("控制面板查找")
set_button_icon(behaviour_buttons["find_control_panel"], "menuIconWindow.png")
# 第二行按钮
behaviour_buttons["select_related_joints"] = QtWidgets.QPushButton("选择关联关节")
set_button_icon(behaviour_buttons["select_related_joints"], "kinJoint.png")
behaviour_buttons["write_current_expression"] = QtWidgets.QPushButton("写入当前表情")
set_button_icon(behaviour_buttons["write_current_expression"], "positionConstraint.png")
behaviour_buttons["write_mirror_expression"] = QtWidgets.QPushButton("写入镜像表情")
set_button_icon(behaviour_buttons["write_mirror_expression"], "mirrorJoint.png")
# 设置所有按钮的样式
for key, button in behaviour_buttons.items():
button.setMinimumHeight(28)
button.setStyleSheet("text-align: left; padding-left: 30px;")
button.setToolTip(button.text())
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建行为系统UI控件
包括按钮、标签、列表等
"""
# 标题标签
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("behaviour_title", "角色行为"))
self.controls["title_label"].setObjectName("behaviourTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("behaviourMainSplitter")
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("behaviourLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("behaviourRightPanel")
# 左侧面板控件
# Blendshape列表
self.controls["blendshape_group"] = QtWidgets.QGroupBox(LANG.get("blendshape_group", "Blendshape列表"))
self.controls["blendshape_group"].setObjectName("blendshapeGroup")
# Blendshape列表
self.controls["blendshape_list"] = QtWidgets.QListWidget()
self.controls["blendshape_list"].setObjectName("blendshapeList")
# Blendshape刷新按钮
self.buttons["refresh_blendshape"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_blendshape"].setObjectName("refreshBlendshapeButton")
# Blendshape过滤组
self.controls["blendshape_filter_group"] = QtWidgets.QGroupBox(LANG.get("blendshape_filter", "Blendshape过滤"))
self.controls["blendshape_filter_group"].setObjectName("blendshapeFilterGroup")
# Blendshape过滤输入框
self.controls["blendshape_filter_input"] = QtWidgets.QLineEdit()
self.controls["blendshape_filter_input"].setObjectName("blendshapeFilterInput")
self.controls["blendshape_filter_input"].setPlaceholderText(LANG.get("filter_placeholder", "输入过滤条件"))
# 次级Blendshape列表组
self.controls["secondary_blendshape_group"] = QtWidgets.QGroupBox(LANG.get("secondary_blendshape_group", "次级Blendshape"))
self.controls["secondary_blendshape_group"].setObjectName("secondaryBlendshapeGroup")
# 次级Blendshape列表
self.controls["secondary_blendshape_list"] = QtWidgets.QListWidget()
self.controls["secondary_blendshape_list"].setObjectName("secondaryBlendshapeList")
# 次级Blendshape刷新按钮
self.buttons["refresh_secondary_blendshape"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_secondary_blendshape"].setObjectName("refreshSecondaryBlendshapeButton")
# 右侧面板控件
# Blendshape操作组
self.controls["blendshape_ops_group"] = QtWidgets.QGroupBox(LANG.get("blendshape_operations", "Blendshape操作"))
self.controls["blendshape_ops_group"].setObjectName("blendshapeOpsGroup")
# Blendshape操作按钮
self.buttons["export_blendshape"] = QtWidgets.QPushButton(LANG.get("export_blendshape", "导出Blendshape"))
self.buttons["import_blendshape"] = QtWidgets.QPushButton(LANG.get("import_blendshape", "导入Blendshape"))
self.buttons["edit_range"] = QtWidgets.QPushButton(LANG.get("edit_range", "编辑范围"))
self.buttons["mirror_blendshape"] = QtWidgets.QPushButton(LANG.get("mirror_blendshape", "镜像Blendshape"))
self.buttons["find_flip_target"] = QtWidgets.QPushButton(LANG.get("find_flip_target", "查找翻转目标"))
# 表情控制组
self.controls["expression_control_group"] = QtWidgets.QGroupBox(LANG.get("expression_control", "表情控制"))
self.controls["expression_control_group"].setObjectName("expressionControlGroup")
# 表情控制按钮
self.buttons["reset_expression"] = QtWidgets.QPushButton(LANG.get("reset_expression", "还原默认表情"))
self.buttons["find_expression"] = QtWidgets.QPushButton(LANG.get("find_expression", "查找选择表情"))
self.buttons["find_control_panel"] = QtWidgets.QPushButton(LANG.get("find_control_panel", "控制面板查找"))
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建行为系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的behaviour_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("behaviour_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
main_layout = QtWidgets.QVBoxLayout(parent_tab)
main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4)
main_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 创建主分割控件
main_splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
# 左侧区域 - Raw Control
left_widget = QtWidgets.QWidget()
left_layout = QtWidgets.QVBoxLayout(left_widget)
left_layout.setContentsMargins(2, 2, 2, 2)
left_layout.setSpacing(2)
# 标题和搜索区域
left_header = QtWidgets.QHBoxLayout()
left_title = QtWidgets.QLabel("Raw Control [000]")
left_title.setStyleSheet("font-weight: bold;")
left_header.addWidget(left_title)
left_layout.addLayout(left_header)
# 搜索框
search_layout = QtWidgets.QHBoxLayout()
search_icon = QtWidgets.QLabel()
search_icon.setPixmap(QtGui.QIcon(":/magnifyGlass.png").pixmap(16, 16))
search_layout.addWidget(search_icon)
search_layout.addWidget(search_input)
left_layout.addLayout(search_layout)
# 主列表
left_layout.addWidget(blendshape_tree)
# 底部按钮组
left_bottom_buttons = QtWidgets.QHBoxLayout()
left_bottom_buttons.addWidget(restore_button)
left_bottom_buttons.addWidget(combo_select_button)
left_layout.addLayout(left_bottom_buttons)
# 数字按钮组
left_layout.addWidget(all_button)
left_layout.addLayout(number_buttons_layout)
# 底部滑块和数值
left_slider_layout = QtWidgets.QHBoxLayout()
left_slider_layout.addWidget(weight_value)
left_slider_layout.addWidget(blendshape_slider)
left_slider_layout.addWidget(QtWidgets.QPushButton("全部"))
left_layout.addLayout(left_slider_layout)
# 左侧底部按钮组
left_bottom_layout = QtWidgets.QHBoxLayout()
left_bottom_layout.addWidget(QtWidgets.QPushButton("定义"))
left_bottom_layout.addWidget(QtWidgets.QPushButton("范围 -"))
left_layout.addLayout(left_bottom_layout)
# 右侧区域 - Related BlendShapes
right_widget = QtWidgets.QWidget()
right_layout = QtWidgets.QVBoxLayout(right_widget)
right_layout.setContentsMargins(2, 2, 2, 2)
right_layout.setSpacing(2)
# 标题
right_header = QtWidgets.QHBoxLayout()
right_title = QtWidgets.QLabel("Related BlendShapes [000]")
right_title.setStyleSheet("font-weight: bold;")
right_header.addWidget(right_title)
right_layout.addLayout(right_header)
# 相关混合变形列表
right_layout.addWidget(sub_blendshape_tree)
# 右侧滑块和数值
right_slider_layout = QtWidgets.QHBoxLayout()
right_slider_layout.addWidget(right_value)
right_slider_layout.addWidget(right_slider)
right_slider_layout.addWidget(QtWidgets.QPushButton("全部"))
right_layout.addLayout(right_slider_layout)
# 右侧按钮组 - 第一行
right_buttons_row1 = QtWidgets.QHBoxLayout()
right_buttons_row1.addWidget(single_target_button)
right_buttons_row1.addWidget(combo_target_button)
right_buttons_row1.addWidget(batch_target_button)
right_layout.addLayout(right_buttons_row1)
# 右侧按钮组 - 第二行
right_buttons_row2 = QtWidgets.QHBoxLayout()
right_buttons_row2.addWidget(add_target_button)
right_buttons_row2.addWidget(remove_target_button)
right_layout.addLayout(right_buttons_row2)
# 右侧按钮组 - 第三行
right_buttons_row3 = QtWidgets.QHBoxLayout()
right_buttons_row3.addWidget(mirror_target_button)
right_buttons_row3.addWidget(flip_target_button)
right_layout.addLayout(right_buttons_row3)
# 添加到主分割控件
main_splitter.addWidget(left_widget)
main_splitter.addWidget(right_widget)
# 设置分割比例
main_splitter.setSizes([int(parent_tab.width() * 0.5), int(parent_tab.width() * 0.5)])
# 底部按钮组
bottom_widget = QtWidgets.QWidget()
bottom_layout = QtWidgets.QVBoxLayout(bottom_widget)
bottom_layout.setContentsMargins(4, 4, 4, 4)
bottom_layout.setSpacing(4)
# 选项卡按钮组
tab_buttons = QtWidgets.QHBoxLayout()
tab_buttons.addWidget(QtWidgets.QPushButton("BS"))
tab_buttons.addWidget(QtWidgets.QPushButton("PSD"))
tab_buttons.addWidget(QtWidgets.QPushButton("KEY"))
tab_buttons.addWidget(QtWidgets.QPushButton("JNT"))
tab_buttons.addWidget(QtWidgets.QPushButton("ARK"))
tab_buttons.addWidget(QtWidgets.QPushButton("CTR"))
bottom_layout.addLayout(tab_buttons)
# 底部滑块
bottom_slider_layout = QtWidgets.QHBoxLayout()
bottom_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
bottom_slider.setMinimum(0)
bottom_slider.setMaximum(1000)
bottom_slider.setValue(0)
bottom_value = QtWidgets.QLineEdit("0.000")
bottom_value.setFixedWidth(50)
bottom_value.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
bottom_slider_layout.addWidget(bottom_value)
bottom_slider_layout.addWidget(bottom_slider)
bottom_slider_layout.addWidget(plus_button)
bottom_slider_layout.addWidget(QtWidgets.QPushButton("全部"))
bottom_layout.addLayout(bottom_slider_layout)
# 底部按钮组 - 第一行
bottom_buttons_row1 = QtWidgets.QHBoxLayout()
bottom_buttons_row1.addWidget(behaviour_buttons["reset_controller"])
bottom_buttons_row1.addWidget(behaviour_buttons["find_expression"])
bottom_buttons_row1.addWidget(behaviour_buttons["write_current_expression"])
bottom_layout.addLayout(bottom_buttons_row1)
# 底部按钮组 - 第二行
bottom_buttons_row2 = QtWidgets.QHBoxLayout()
bottom_buttons_row2.addWidget(behaviour_buttons["find_control_panel"])
bottom_buttons_row2.addWidget(behaviour_buttons["select_related_joints"])
bottom_buttons_row2.addWidget(behaviour_buttons["write_mirror_expression"])
bottom_layout.addLayout(bottom_buttons_row2)
# 添加到主布局
main_layout.addWidget(main_splitter, 3) # 占据更多空间
main_layout.addWidget(bottom_widget, 1) # 占据较少空间
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建行为系统UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加主分割器
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 将左右面板添加到主分割器
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# Blendshape列表组布局
self.layouts["blendshape_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshape_group"])
self.layouts["blendshape_layout"].addWidget(self.controls["blendshape_list"])
self.layouts["blendshape_layout"].addWidget(self.buttons["refresh_blendshape"])
# Blendshape过滤组布局
self.layouts["blendshape_filter_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshape_filter_group"])
self.layouts["blendshape_filter_layout"].addWidget(self.controls["blendshape_filter_input"])
# 次级Blendshape列表组布局
self.layouts["secondary_blendshape_layout"] = QtWidgets.QVBoxLayout(self.controls["secondary_blendshape_group"])
self.layouts["secondary_blendshape_layout"].addWidget(self.controls["secondary_blendshape_list"])
self.layouts["secondary_blendshape_layout"].addWidget(self.buttons["refresh_secondary_blendshape"])
# 添加组到左侧面板布局
self.layouts["left_layout"].addWidget(self.controls["blendshape_group"])
self.layouts["left_layout"].addWidget(self.controls["blendshape_filter_group"])
self.layouts["left_layout"].addWidget(self.controls["secondary_blendshape_group"])
self.layouts["left_layout"].addStretch()
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# Blendshape操作组布局
self.layouts["blendshape_ops_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshape_ops_group"])
self.layouts["blendshape_ops_layout"].addWidget(self.buttons["export_blendshape"])
self.layouts["blendshape_ops_layout"].addWidget(self.buttons["import_blendshape"])
self.layouts["blendshape_ops_layout"].addWidget(self.buttons["edit_range"])
self.layouts["blendshape_ops_layout"].addWidget(self.buttons["mirror_blendshape"])
self.layouts["blendshape_ops_layout"].addWidget(self.buttons["find_flip_target"])
# 表情控制组布局
self.layouts["expression_control_layout"] = QtWidgets.QVBoxLayout(self.controls["expression_control_group"])
self.layouts["expression_control_layout"].addWidget(self.buttons["reset_expression"])
self.layouts["expression_control_layout"].addWidget(self.buttons["find_expression"])
self.layouts["expression_control_layout"].addWidget(self.buttons["find_control_panel"])
# 添加组到右侧面板布局
self.layouts["right_layout"].addWidget(self.controls["blendshape_ops_group"])
self.layouts["right_layout"].addWidget(self.controls["expression_control_group"])
self.layouts["right_layout"].addStretch()
# 创建分割器大小处理器
self.resize_handlers["main_splitter"] = ui_utils.SplitterResizeHandler(
self.main_widget, self.splitters["main_splitter"], is_horizontal=True
)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接行为系统UI信号和槽
"""
# 连接主表情控制列表选择事件
blendshape_tree.itemSelectionChanged.connect(on_blendshape_selection_changed)
sub_blendshape_tree.itemSelectionChanged.connect(on_sub_blendshape_selection_changed)
# 连接滑块值变化事件
blendshape_slider.valueChanged.connect(on_blendshape_slider_changed)
# 连接底部按钮点击事件
behaviour_buttons["reset_controller"].clicked.connect(on_reset_controller)
behaviour_buttons["find_expression"].clicked.connect(on_find_expression)
behaviour_buttons["find_control_panel"].clicked.connect(on_find_control_panel)
behaviour_buttons["select_related_joints"].clicked.connect(on_select_related_joints)
behaviour_buttons["write_current_expression"].clicked.connect(on_write_current_expression)
behaviour_buttons["write_mirror_expression"].clicked.connect(on_write_mirror_expression)
# 连接其他按钮点击事件
restore_button.clicked.connect(on_restore_expression)
combo_select_button.clicked.connect(on_combo_select)
# 连接右侧按钮点击事件
single_target_button.clicked.connect(on_single_target)
combo_target_button.clicked.connect(on_combo_target)
batch_target_button.clicked.connect(on_batch_target)
add_target_button.clicked.connect(on_add_target)
remove_target_button.clicked.connect(on_remove_target)
mirror_target_button.clicked.connect(on_mirror_target)
flip_target_button.clicked.connect(on_flip_target)
#===================================== CALLBACK FUNCTIONS ===================================
def on_blendshape_selection_changed():
"""当主表情控制列表选择变化时调用"""
print("主表情控制选择已更改")
# TODO: 实现选择变化后的逻辑
def on_sub_blendshape_selection_changed():
"""当相关混合变形列表选择变化时调用"""
print("相关混合变形选择已更改")
# TODO: 实现选择变化后的逻辑
def on_blendshape_slider_changed(value):
"""当混合变形滑块值变化时调用"""
actual_value = value / 1000.0 # 转换为0-1范围
print(f"混合变形权重已更改为: {actual_value:.3f}")
# TODO: 实现权重变化后的逻辑
def on_reset_controller():
"""还原默认表情"""
print("还原默认表情功能待实现")
# TODO: 实现还原默认表情功能
def on_find_expression():
"""查找选择表情"""
print("查找选择表情功能待实现")
# TODO: 实现查找选择表情功能
def on_find_control_panel():
"""控制面板查找"""
print("控制面板查找功能待实现")
# TODO: 实现控制面板查找功能
def on_select_related_joints():
"""选择关联关节"""
print("选择关联关节功能待实现")
# TODO: 实现选择关联关节功能
def on_write_current_expression():
"""写入当前表情"""
print("写入当前表情功能待实现")
# TODO: 实现写入当前表情功能
def on_write_mirror_expression():
"""写入镜像表情"""
print("写入镜像表情功能待实现")
# TODO: 实现写入镜像表情功能
def on_restore_expression():
"""恢复表情"""
print("恢复表情功能待实现")
# TODO: 实现恢复表情功能
def on_combo_select():
"""组合选择"""
print("组合选择功能待实现")
# TODO: 实现组合选择功能
def on_single_target():
"""单个目标表情"""
print("单个目标表情功能待实现")
# TODO: 实现单个目标表情功能
def on_combo_target():
"""复合目标表情"""
print("复合目标表情功能待实现")
# TODO: 实现复合目标表情功能
def on_batch_target():
"""批量目标表情"""
print("批量目标表情功能待实现")
# TODO: 实现批量目标表情功能
def on_add_target():
"""添加目标表情"""
print("添加目标表情功能待实现")
# TODO: 实现添加目标表情功能
def on_remove_target():
"""移除目标表情"""
print("移除目标表情功能待实现")
# TODO: 实现移除目标表情功能
def on_mirror_target():
"""镜像目标表情"""
print("镜像目标表情功能待实现")
# TODO: 实现镜像目标表情功能
def on_flip_target():
"""翻转目标表情"""
print("翻转目标表情功能待实现")
# TODO: 实现翻转目标表情功能
#===================================== PLACEHOLDER FUNCTION ===================================
def behaviour_temp_function():
return utils_behaviour.behaviour_temp_utils_function()
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# Blendshape列表按钮连接
self.buttons["refresh_blendshape"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
# Blendshape过滤连接
self.controls["blendshape_filter_input"].textChanged.connect(utils_behaviour.behaviour_temp_utils_function)
# 次级Blendshape按钮连接
self.buttons["refresh_secondary_blendshape"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
# Blendshape操作按钮连接
self.buttons["export_blendshape"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["import_blendshape"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["edit_range"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["mirror_blendshape"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["find_flip_target"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
# 表情控制按钮连接
self.buttons["reset_expression"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["find_expression"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)
self.buttons["find_control_panel"].clicked.connect(utils_behaviour.behaviour_temp_utils_function)

View File

@@ -10,459 +10,266 @@ Definition UI Module for Plugin
- 创建:创建混合变形,绑定蒙皮,取消蒙皮
- 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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 FUNCTIONS ===================================
from scripts.utils import utils_definition as utils_definition
from scripts.ui import ui_utils
from scripts.utils import utils_definition
#========================================== 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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
definition_tabs = None
dna_elements = {}
definition_buttons = {}
class DefinitionUI(ui_utils.BaseUI):
"""
定义系统UI类 - 负责显示DNA定义编辑界面和基础操作
继承自BaseUI类实现DNA定义相关的UI功能
"""
#========================================== INIT ========================================
def __init__(self):
"""
初始化定义系统UI
创建主控件和布局,并连接信号和槽
"""
super(DefinitionUI, self).__init__()
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("definitionMainWidget")
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
def set_button_icon(button, icon_name):
"""
设置按钮图标使用Maya默认图标
Args:
button: 要设置图标的按钮
icon_name: 图标文件名
"""
# 使用Maya内置图标
from maya import cmds
# 设置按钮图标使用Maya的图标
button.setIcon(QtGui.QIcon(":/{}".format(icon_name)))
button.setIconSize(QtCore.QSize(24, 24)) # 图标尺寸
print(f"成功设置按钮图标: {icon_name}")
# 注意:如果图标加载失败,我们会看到一个空图标,但不会引起错误
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建定义系统UI控件
包括按钮、标签、列表等
"""
# 标题标签
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("definition_title", "DNA定义"))
self.controls["title_label"].setObjectName("definitionTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("definitionMainSplitter")
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("definitionLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("definitionRightPanel")
# 左侧面板控件
# LOD组
self.controls["lod_group"] = QtWidgets.QGroupBox(LANG.get("lod_group", "LOD"))
self.controls["lod_group"].setObjectName("lodGroup")
# LOD列表
self.controls["lod_list"] = QtWidgets.QListWidget()
self.controls["lod_list"].setObjectName("lodList")
# LOD刷新按钮
self.buttons["refresh_lod"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_lod"].setObjectName("refreshLodButton")
# Meshes组
self.controls["meshes_group"] = QtWidgets.QGroupBox(LANG.get("meshes_group", "几何体"))
self.controls["meshes_group"].setObjectName("meshesGroup")
# Meshes列表
self.controls["meshes_list"] = QtWidgets.QListWidget()
self.controls["meshes_list"].setObjectName("meshesList")
# Meshes刷新按钮
self.buttons["refresh_meshes"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_meshes"].setObjectName("refreshMeshesButton")
# Joints组
self.controls["joints_group"] = QtWidgets.QGroupBox(LANG.get("joints_group", "关节"))
self.controls["joints_group"].setObjectName("jointsGroup")
# Joints列表
self.controls["joints_list"] = QtWidgets.QListWidget()
self.controls["joints_list"].setObjectName("jointsList")
# Joints刷新按钮
self.buttons["refresh_joints"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_joints"].setObjectName("refreshJointsButton")
# 右侧面板控件
# 写入组
self.controls["write_group"] = QtWidgets.QGroupBox(LANG.get("write_group", "写入"))
self.controls["write_group"].setObjectName("writeGroup")
# 写入按钮
self.buttons["write_joint_default"] = QtWidgets.QPushButton(LANG.get("write_joint_default", "写入关节默认位置"))
self.buttons["write_geometry"] = QtWidgets.QPushButton(LANG.get("write_geometry", "写入几何体"))
self.buttons["write_skinning"] = QtWidgets.QPushButton(LANG.get("write_skinning", "写入蒙皮"))
self.buttons["write_blendshape"] = QtWidgets.QPushButton(LANG.get("write_blendshape", "写入混合变形目标"))
# 创建组
self.controls["create_group"] = QtWidgets.QGroupBox(LANG.get("create_group", "创建"))
self.controls["create_group"].setObjectName("createGroup")
# 创建按钮
self.buttons["create_blendshape"] = QtWidgets.QPushButton(LANG.get("create_blendshape", "创建混合变形"))
self.buttons["bind_skin"] = QtWidgets.QPushButton(LANG.get("bind_skin", "绑定蒙皮"))
self.buttons["unbind_skin"] = QtWidgets.QPushButton(LANG.get("unbind_skin", "取消蒙皮"))
# 工具组
self.controls["tools_group"] = QtWidgets.QGroupBox(LANG.get("tools_group", "工具"))
self.controls["tools_group"].setObjectName("toolsGroup")
# 工具按钮
self.buttons["reposition_head_joints"] = QtWidgets.QPushButton(LANG.get("reposition_head_joints", "重新定位头部关节"))
self.buttons["reposition_body_joints"] = QtWidgets.QPushButton(LANG.get("reposition_body_joints", "重新定位身体关节"))
self.buttons["reposition_all_joints"] = QtWidgets.QPushButton(LANG.get("reposition_all_joints", "重新定位全身关节"))
self.buttons["quick_preset"] = QtWidgets.QPushButton(LANG.get("quick_preset", "快速创建预设"))
def widgets():
"""
创建定义系统UI控件
"""
global definition_tabs, dna_elements, definition_buttons
# 创建子标签页
definition_tabs = QtWidgets.QTabWidget()
# 创建各类元素列表
dna_elements["lod_list"] = QtWidgets.QListWidget()
dna_elements["lod_list"].setObjectName("LodList")
dna_elements["mesh_list"] = QtWidgets.QListWidget()
dna_elements["mesh_list"].setObjectName("MeshList")
dna_elements["joint_list"] = QtWidgets.QListWidget()
dna_elements["joint_list"].setObjectName("JointList")
dna_elements["blendshape_list"] = QtWidgets.QListWidget()
dna_elements["blendshape_list"].setObjectName("BlendshapeList")
dna_elements["animmap_list"] = QtWidgets.QListWidget()
dna_elements["animmap_list"].setObjectName("AnimatedMapList")
# 创建元素信息面板
dna_elements["element_info"] = QtWidgets.QTextEdit()
dna_elements["element_info"].setReadOnly(True)
dna_elements["element_info"].setObjectName("ElementInfo")
# 创建列表标题标签
dna_elements["lod_label"] = QtWidgets.QLabel("LODs [000]")
dna_elements["mesh_label"] = QtWidgets.QLabel("Meshes [000]")
dna_elements["joint_label"] = QtWidgets.QLabel("Joints [000]")
dna_elements["blendshape_label"] = QtWidgets.QLabel("BlendShapes [000]")
dna_elements["animmap_label"] = QtWidgets.QLabel("AnimatedMap [000]")
# 创建刷新按钮
dna_elements["refresh_lod"] = QtWidgets.QPushButton("刷新")
dna_elements["refresh_lod"].setObjectName("RefreshButton")
dna_elements["refresh_lod"].setFixedWidth(60)
dna_elements["refresh_mesh"] = QtWidgets.QPushButton("刷新")
dna_elements["refresh_mesh"].setObjectName("RefreshButton")
dna_elements["refresh_mesh"].setFixedWidth(60)
dna_elements["refresh_joint"] = QtWidgets.QPushButton("刷新")
dna_elements["refresh_joint"].setObjectName("RefreshButton")
dna_elements["refresh_joint"].setFixedWidth(60)
dna_elements["refresh_blendshape"] = QtWidgets.QPushButton("刷新")
dna_elements["refresh_blendshape"].setObjectName("RefreshButton")
dna_elements["refresh_blendshape"].setFixedWidth(60)
dna_elements["refresh_animmap"] = QtWidgets.QPushButton("刷新")
dna_elements["refresh_animmap"].setObjectName("RefreshButton")
dna_elements["refresh_animmap"].setFixedWidth(60)
# 创建LOD和Meshes特殊按钮
dna_elements["define_lod_joint"] = QtWidgets.QPushButton("定义LOD关节")
set_button_icon(dna_elements["define_lod_joint"], "layerEditor.png")
dna_elements["define_lod_joint"].setMinimumHeight(28)
dna_elements["define_lod_joint"].setStyleSheet("text-align: left; padding-left: 30px;")
dna_elements["define_lod_joint"].setToolTip("定义LOD关节")
dna_elements["create_geometry"] = QtWidgets.QPushButton("创建几何体")
set_button_icon(dna_elements["create_geometry"], "polyCube.png")
dna_elements["create_geometry"].setMinimumHeight(28)
dna_elements["create_geometry"].setStyleSheet("text-align: left; padding-left: 30px;")
dna_elements["create_geometry"].setToolTip("创建几何体")
# 功能按钮
# 写入组按钮
definition_buttons["write_joint_defaults"] = QtWidgets.QPushButton("写入关节默认位置")
set_button_icon(definition_buttons["write_joint_defaults"], "HIKCharacterToolBodyPart.png")
definition_buttons["write_geometry"] = QtWidgets.QPushButton("写入几何体")
set_button_icon(definition_buttons["write_geometry"], "polyCube.png")
definition_buttons["write_skinning"] = QtWidgets.QPushButton("写入蒙皮权重")
set_button_icon(definition_buttons["write_skinning"], "paintSkinWeights.png")
definition_buttons["write_blendshapes"] = QtWidgets.QPushButton("写入混合变形目标")
set_button_icon(definition_buttons["write_blendshapes"], "blendShape.png")
# 创建组按钮
definition_buttons["create_blendshapes"] = QtWidgets.QPushButton("创建混合变形")
set_button_icon(definition_buttons["create_blendshapes"], "blendShapeEditor.png")
definition_buttons["bind_skin"] = QtWidgets.QPushButton("绑定蒙皮")
set_button_icon(definition_buttons["bind_skin"], "smoothSkin.png")
definition_buttons["unbind_skin"] = QtWidgets.QPushButton("取消蒙皮")
set_button_icon(definition_buttons["unbind_skin"], "detachSkin.png")
# 工具组按钮
definition_buttons["reposition_head"] = QtWidgets.QPushButton("重新定位头部关节")
set_button_icon(definition_buttons["reposition_head"], "HIKCharacterToolSkeleton.png")
definition_buttons["reposition_body"] = QtWidgets.QPushButton("重新定位身体关节")
set_button_icon(definition_buttons["reposition_body"], "HIKCharacterToolSkeleton.png")
definition_buttons["reposition_all"] = QtWidgets.QPushButton("重新定位全身关节")
set_button_icon(definition_buttons["reposition_all"], "HIKCharacterToolSkeleton.png")
definition_buttons["quick_preset"] = QtWidgets.QPushButton("快速创建预设")
set_button_icon(definition_buttons["quick_preset"], "QR_QuickRigTool.png")
# 设置按钮样式
for button in definition_buttons.values():
button.setMinimumHeight(28)
# 设置按钮文本对齐方式,使图标在左侧,文本在右侧
button.setStyleSheet("text-align: left; padding-left: 30px;")
# 设置工具提示与按钮文本相同
button.setToolTip(button.text())
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建定义系统UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加主分割器
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 将左右面板添加到主分割器
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# LOD组布局
self.layouts["lod_layout"] = QtWidgets.QVBoxLayout(self.controls["lod_group"])
self.layouts["lod_layout"].addWidget(self.controls["lod_list"])
self.layouts["lod_layout"].addWidget(self.buttons["refresh_lod"])
# Meshes组布局
self.layouts["meshes_layout"] = QtWidgets.QVBoxLayout(self.controls["meshes_group"])
self.layouts["meshes_layout"].addWidget(self.controls["meshes_list"])
self.layouts["meshes_layout"].addWidget(self.buttons["refresh_meshes"])
# Joints组布局
self.layouts["joints_layout"] = QtWidgets.QVBoxLayout(self.controls["joints_group"])
self.layouts["joints_layout"].addWidget(self.controls["joints_list"])
self.layouts["joints_layout"].addWidget(self.buttons["refresh_joints"])
# 添加组到左侧面板布局
self.layouts["left_layout"].addWidget(self.controls["lod_group"])
self.layouts["left_layout"].addWidget(self.controls["meshes_group"])
self.layouts["left_layout"].addWidget(self.controls["joints_group"])
self.layouts["left_layout"].addStretch()
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# 写入组布局
self.layouts["write_layout"] = QtWidgets.QVBoxLayout(self.controls["write_group"])
self.layouts["write_layout"].addWidget(self.buttons["write_joint_default"])
self.layouts["write_layout"].addWidget(self.buttons["write_geometry"])
self.layouts["write_layout"].addWidget(self.buttons["write_skinning"])
self.layouts["write_layout"].addWidget(self.buttons["write_blendshape"])
# 创建组布局
self.layouts["create_layout"] = QtWidgets.QVBoxLayout(self.controls["create_group"])
self.layouts["create_layout"].addWidget(self.buttons["create_blendshape"])
self.layouts["create_layout"].addWidget(self.buttons["bind_skin"])
self.layouts["create_layout"].addWidget(self.buttons["unbind_skin"])
# 工具组布局
self.layouts["tools_layout"] = QtWidgets.QVBoxLayout(self.controls["tools_group"])
self.layouts["tools_layout"].addWidget(self.buttons["reposition_head_joints"])
self.layouts["tools_layout"].addWidget(self.buttons["reposition_body_joints"])
self.layouts["tools_layout"].addWidget(self.buttons["reposition_all_joints"])
self.layouts["tools_layout"].addWidget(self.buttons["quick_preset"])
# 添加组到右侧面板布局
self.layouts["right_layout"].addWidget(self.controls["write_group"])
self.layouts["right_layout"].addWidget(self.controls["create_group"])
self.layouts["right_layout"].addWidget(self.controls["tools_group"])
self.layouts["right_layout"].addStretch()
# 创建分割器大小处理器
self.resize_handlers["main_splitter"] = ui_utils.SplitterResizeHandler(
self.main_widget, self.splitters["main_splitter"], is_horizontal=True
)
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建定义系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的definition_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("definition_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建主分割控件 - 水平分割
main_splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
# 创建左侧区域 - 垂直分割
left_splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 创建LOD区域
lod_widget = QtWidgets.QWidget()
lod_layout = QtWidgets.QVBoxLayout(lod_widget)
lod_layout.setContentsMargins(4, 4, 4, 4)
lod_layout.setSpacing(4)
# LOD标题栏
lod_header = QtWidgets.QWidget()
lod_header_layout = QtWidgets.QHBoxLayout(lod_header)
lod_header_layout.setContentsMargins(0, 0, 0, 0)
lod_header_layout.addWidget(dna_elements["lod_label"])
lod_header_layout.addStretch()
lod_header_layout.addWidget(dna_elements["refresh_lod"])
lod_layout.addWidget(lod_header)
lod_layout.addWidget(dna_elements["lod_list"])
lod_layout.addWidget(dna_elements["define_lod_joint"])
# 创建Meshes区域
mesh_widget = QtWidgets.QWidget()
mesh_layout = QtWidgets.QVBoxLayout(mesh_widget)
mesh_layout.setContentsMargins(4, 4, 4, 4)
mesh_layout.setSpacing(4)
# Meshes标题栏
mesh_header = QtWidgets.QWidget()
mesh_header_layout = QtWidgets.QHBoxLayout(mesh_header)
mesh_header_layout.setContentsMargins(0, 0, 0, 0)
mesh_header_layout.addWidget(dna_elements["mesh_label"])
mesh_header_layout.addStretch()
mesh_header_layout.addWidget(dna_elements["refresh_mesh"])
mesh_layout.addWidget(mesh_header)
mesh_layout.addWidget(dna_elements["mesh_list"])
mesh_layout.addWidget(dna_elements["create_geometry"])
# 添加到左侧垂直分割控件
left_splitter.addWidget(lod_widget)
left_splitter.addWidget(mesh_widget)
# 创建右侧区域 - 垂直分割
right_splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 创建右上区域 - Joints
right_top_widget = QtWidgets.QWidget()
right_top_layout = QtWidgets.QVBoxLayout(right_top_widget)
right_top_layout.setContentsMargins(4, 4, 4, 4)
right_top_layout.setSpacing(4)
# Joints标题栏
joint_header = QtWidgets.QWidget()
joint_header_layout = QtWidgets.QHBoxLayout(joint_header)
joint_header_layout.setContentsMargins(0, 0, 0, 0)
joint_header_layout.addWidget(dna_elements["joint_label"])
joint_header_layout.addStretch()
joint_header_layout.addWidget(dna_elements["refresh_joint"])
right_top_layout.addWidget(joint_header)
right_top_layout.addWidget(dna_elements["joint_list"])
# 创建右中区域 - BlendShapes
right_middle_widget = QtWidgets.QWidget()
right_middle_layout = QtWidgets.QVBoxLayout(right_middle_widget)
right_middle_layout.setContentsMargins(4, 4, 4, 4)
right_middle_layout.setSpacing(4)
# BlendShapes标题栏
blendshape_header = QtWidgets.QWidget()
blendshape_header_layout = QtWidgets.QHBoxLayout(blendshape_header)
blendshape_header_layout.setContentsMargins(0, 0, 0, 0)
blendshape_header_layout.addWidget(dna_elements["blendshape_label"])
blendshape_header_layout.addStretch()
blendshape_header_layout.addWidget(dna_elements["refresh_blendshape"])
right_middle_layout.addWidget(blendshape_header)
right_middle_layout.addWidget(dna_elements["blendshape_list"])
# 创建右下区域 - AnimatedMap
right_bottom_widget = QtWidgets.QWidget()
right_bottom_layout = QtWidgets.QVBoxLayout(right_bottom_widget)
right_bottom_layout.setContentsMargins(4, 4, 4, 4)
right_bottom_layout.setSpacing(4)
# AnimatedMap标题栏
animmap_header = QtWidgets.QWidget()
animmap_header_layout = QtWidgets.QHBoxLayout(animmap_header)
animmap_header_layout.setContentsMargins(0, 0, 0, 0)
animmap_header_layout.addWidget(dna_elements["animmap_label"])
animmap_header_layout.addStretch()
animmap_header_layout.addWidget(dna_elements["refresh_animmap"])
right_bottom_layout.addWidget(animmap_header)
right_bottom_layout.addWidget(dna_elements["animmap_list"])
# 添加到右侧分割控件
right_splitter.addWidget(right_top_widget)
right_splitter.addWidget(right_middle_widget)
right_splitter.addWidget(right_bottom_widget)
# 设置右侧分割控件比例
right_splitter.setSizes([200, 200, 200])
# 设置左侧分割控件比例 - 使其均等
left_splitter.setSizes([300, 300])
# 设置左侧分割控件的伸缩因子,使两个模块均等分配空间
left_splitter.setStretchFactor(0, 1) # LOD区域伸缩因子为1
left_splitter.setStretchFactor(1, 1) # Meshes区域伸缩因子为1
# 添加到主分割控件
main_splitter.addWidget(left_splitter)
main_splitter.addWidget(right_splitter)
# 设置主分割控件比例 - 左右宽度相等
main_splitter.setSizes([500, 500])
# 设置分割控件的伸缩因子,使其根据窗口大小均等分配空间
main_splitter.setStretchFactor(0, 1) # 左侧伸缩因子为1
main_splitter.setStretchFactor(1, 1) # 右侧伸缩因子为1
# 创建底部功能区域
bottom_widget = QtWidgets.QWidget()
bottom_layout = QtWidgets.QHBoxLayout(bottom_widget)
bottom_layout.setContentsMargins(4, 4, 4, 4)
# 创建功能分组
write_group = QtWidgets.QGroupBox("写入")
write_layout = QtWidgets.QVBoxLayout(write_group)
write_layout.setAlignment(QtCore.Qt.AlignTop) # 设置向顶部对齐
write_layout.setContentsMargins(4, 8, 4, 4) # 减小内边距
write_layout.setSpacing(4) # 减小间距
write_layout.addWidget(definition_buttons["write_joint_defaults"])
write_layout.addWidget(definition_buttons["write_geometry"])
write_layout.addWidget(definition_buttons["write_skinning"])
write_layout.addWidget(definition_buttons["write_blendshapes"])
write_layout.addStretch() # 添加弹性空间,使按钮向顶部对齐
create_group = QtWidgets.QGroupBox("创建")
create_layout = QtWidgets.QVBoxLayout(create_group)
create_layout.setAlignment(QtCore.Qt.AlignTop) # 设置向顶部对齐
create_layout.setContentsMargins(4, 8, 4, 4) # 减小内边距
create_layout.setSpacing(4) # 减小间距
create_layout.addWidget(definition_buttons["create_blendshapes"])
create_layout.addWidget(definition_buttons["bind_skin"])
create_layout.addWidget(definition_buttons["unbind_skin"])
create_layout.addStretch() # 添加弹性空间,使按钮向顶部对齐
tools_group = QtWidgets.QGroupBox("工具")
tools_layout = QtWidgets.QVBoxLayout(tools_group)
tools_layout.setAlignment(QtCore.Qt.AlignTop) # 设置向顶部对齐
tools_layout.setContentsMargins(4, 8, 4, 4) # 减小内边距
tools_layout.setSpacing(4) # 减小间距
tools_layout.addWidget(definition_buttons["reposition_head"])
tools_layout.addWidget(definition_buttons["reposition_body"])
tools_layout.addWidget(definition_buttons["reposition_all"])
tools_layout.addWidget(definition_buttons["quick_preset"])
tools_layout.addStretch() # 添加弹性空间,使按钮向顶部对齐
# 添加到底部布局
bottom_layout.addWidget(write_group)
bottom_layout.addWidget(create_group)
bottom_layout.addWidget(tools_group)
# 创建主容器
main_container = QtWidgets.QWidget()
container_layout = QtWidgets.QVBoxLayout(main_container)
container_layout.setContentsMargins(0, 0, 0, 0)
container_layout.setSpacing(4)
container_layout.addWidget(main_splitter, 1)
container_layout.addWidget(bottom_widget, 0)
# 添加到主布局
main_layout.addWidget(main_container)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接定义系统UI信号和槽
"""
# 连接功能按钮点击事件
definition_buttons["write_joint_defaults"].clicked.connect(lambda: print("写入关节默认位置功能待实现"))
definition_buttons["write_geometry"].clicked.connect(lambda: print("写入几何体功能待实现"))
definition_buttons["write_skinning"].clicked.connect(lambda: print("写入蒙皮功能待实现"))
definition_buttons["write_blendshapes"].clicked.connect(lambda: print("写入混合变形目标功能待实现"))
definition_buttons["create_blendshapes"].clicked.connect(lambda: print("创建混合变形功能待实现"))
definition_buttons["bind_skin"].clicked.connect(lambda: print("绑定蒙皮功能待实现"))
definition_buttons["unbind_skin"].clicked.connect(lambda: print("取消蒙皮功能待实现"))
definition_buttons["reposition_head"].clicked.connect(lambda: print("重新定位头部关节功能待实现"))
definition_buttons["reposition_body"].clicked.connect(lambda: print("重新定位身体关节功能待实现"))
definition_buttons["reposition_all"].clicked.connect(lambda: print("重新定位全身关节功能待实现"))
definition_buttons["quick_preset"].clicked.connect(lambda: print("快速创建预设功能待实现"))
# 连接列表选择事件
for key, widget in dna_elements.items():
if isinstance(widget, QtWidgets.QListWidget):
widget.itemSelectionChanged.connect(lambda k=key: on_list_selection_changed(k))
widget.itemDoubleClicked.connect(lambda item, k=key: on_list_item_double_clicked(item, k))
# 连接刷新按钮点击事件
dna_elements["refresh_lod"].clicked.connect(lambda: refresh_list("lod_list"))
dna_elements["refresh_mesh"].clicked.connect(lambda: refresh_list("mesh_list"))
dna_elements["refresh_joint"].clicked.connect(lambda: refresh_list("joint_list"))
dna_elements["refresh_blendshape"].clicked.connect(lambda: refresh_list("blendshape_list"))
dna_elements["refresh_animmap"].clicked.connect(lambda: refresh_list("animmap_list"))
# 连接LOD和Meshes特殊按钮点击事件
dna_elements["define_lod_joint"].clicked.connect(lambda: print("定义LOD关节功能待实现"))
dna_elements["create_geometry"].clicked.connect(lambda: print("创建几何体功能待实现"))
# 列表选择变化处理函数
def on_list_selection_changed(list_key):
"""
处理列表选择变化事件
Args:
list_key: 列表键名
"""
selected_items = dna_elements[list_key].selectedItems()
if selected_items:
item = selected_items[0]
info_text = f"选中的{list_key.split('_')[0]}: {item.text()}\n"
info_text += f"\n属性信息将在此显示"
dna_elements["element_info"].setText(info_text)
print(f"{list_key} 选中项: {item.text()}")
# 列表项双击处理函数
def on_list_item_double_clicked(item, list_key):
"""
处理列表项双击事件
Args:
item: 被双击的列表项
list_key: 列表键名
"""
print(f"{list_key} 双击项: {item.text()}")
# 刷新列表函数
def refresh_list(list_key):
"""
刷新指定列表
Args:
list_key: 要刷新的列表键名
"""
list_widget = dna_elements[list_key]
list_widget.clear()
# 模拟数据加载
test_data = {
"lod_list": ["LOD_0", "LOD_1", "LOD_2"],
"mesh_list": ["Head", "Body", "Eyes", "Teeth", "Tongue"],
"joint_list": ["Head_Joint", "Neck_Joint", "Spine_Joint", "Arm_L_Joint", "Arm_R_Joint"],
"blendshape_list": ["Smile", "Frown", "Blink", "Jaw_Open", "Brow_Raise"],
"animmap_list": ["FaceMap_01", "BodyMap_01", "ExpressionMap_01"]
}
# 添加测试数据到列表
if list_key in test_data:
for item in test_data[list_key]:
list_widget.addItem(item)
# 更新对应标签的计数
label_key = list_key.replace("list", "label")
if label_key in dna_elements:
count = list_widget.count()
label_text = f"{label_key.split('_')[0].capitalize()}s [{count:03d}]"
dna_elements[label_key].setText(label_text)
print(f"刷新{list_key}完成")
#===================================== PLACEHOLDER FUNCTION ===================================
def definition_temp_function():
utils_definition.definition_temp_utils_function
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# 刷新按钮连接
self.buttons["refresh_lod"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["refresh_meshes"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["refresh_joints"].clicked.connect(utils_definition.definition_temp_utils_function)
# 写入按钮连接
self.buttons["write_joint_default"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["write_geometry"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["write_skinning"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["write_blendshape"].clicked.connect(utils_definition.definition_temp_utils_function)
# 创建按钮连接
self.buttons["create_blendshape"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["bind_skin"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["unbind_skin"].clicked.connect(utils_definition.definition_temp_utils_function)
# 工具按钮连接
self.buttons["reposition_head_joints"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["reposition_body_joints"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["reposition_all_joints"].clicked.connect(utils_definition.definition_temp_utils_function)
self.buttons["quick_preset"].clicked.connect(utils_definition.definition_temp_utils_function)

View File

@@ -11,159 +11,232 @@ Geometry UI Module for Plugin
- 自动加载模型
- 标准化命名
- 自动分组
- 生成面部配件(毛,舌头,泪腺 等)
- 生成面部配件(毛,舌头,泪腺 等)
- 修复接缝(修复法线)
- 修复点序
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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 FUNCTIONS ===================================
from scripts.utils import utils_geometry as utils_geometry
from scripts.ui import ui_utils
from scripts.utils import utils_geometry
#========================================== 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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
model_tree = None
lod_combo = None
model_buttons = {}
model_info_panel = None
class GeometryUI(ui_utils.BaseUI):
"""
几何模型UI类 - 负责显示几何模型编辑界面和基础操作
继承自BaseUI类实现几何模型相关的UI功能
"""
#========================================== INIT ========================================
def __init__(self):
"""
初始化几何模型UI
创建主控件和布局,并连接信号和槽
"""
super(GeometryUI, self).__init__()
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("geometryMainWidget")
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
def widgets():
"""
创建几何模型UI控件
"""
global model_tree, lod_combo, model_buttons, model_info_panel
# LOD选择下拉菜单
lod_combo = QtWidgets.QComboBox()
lod_combo.addItems(["LOD0", "LOD1", "LOD2", "LOD3", "LOD4"])
lod_combo.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
lod_combo.setMinimumWidth(100)
# 模型树形视图
model_tree = QtWidgets.QTreeWidget()
model_tree.setHeaderLabels(["模型名称", "顶点数", "面数"])
model_tree.setMinimumHeight(250)
model_tree.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
model_tree.header().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) # 列自动拉伸
# 模型信息面板
model_info_panel = QtWidgets.QTextEdit()
model_info_panel.setReadOnly(True)
model_info_panel.setMinimumHeight(100)
model_info_panel.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 功能按钮 - 设置统一的大小策略
for button_name in ["load_model", "create_lod", "auto_load", "standardize_name",
"auto_group", "generate_accessories", "fix_seams", "fix_vertex_order"]:
model_buttons[button_name] = QtWidgets.QPushButton({
"load_model": "加载模型",
"create_lod": "创建LOD",
"auto_load": "自动加载",
"standardize_name": "标准化命名",
"auto_group": "自动分组",
"generate_accessories": "生成面部配件",
"fix_seams": "修复接缝",
"fix_vertex_order": "修复点序"
}[button_name])
model_buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
model_buttons[button_name].setMinimumWidth(120)
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建几何模型UI控件
包括按钮、标签、列表等
"""
# 标题标签
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("geometry_title", "几何模型"))
self.controls["title_label"].setObjectName("geometryTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("geometryMainSplitter")
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("geometryLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("geometryRightPanel")
# 左侧面板控件
# 模型列表组
self.controls["model_group"] = QtWidgets.QGroupBox(LANG.get("model_group", "模型列表"))
self.controls["model_group"].setObjectName("modelGroup")
# 模型列表
self.controls["model_list"] = QtWidgets.QListWidget()
self.controls["model_list"].setObjectName("modelList")
# 模型刷新按钮
self.buttons["refresh_models"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_models"].setObjectName("refreshModelsButton")
# LOD过滤组
self.controls["lod_filter_group"] = QtWidgets.QGroupBox(LANG.get("lod_filter_group", "LOD过滤"))
self.controls["lod_filter_group"].setObjectName("lodFilterGroup")
# LOD选择
self.controls["lod_label"] = QtWidgets.QLabel(LANG.get("lod", "LOD:"))
self.controls["lod_combo"] = QtWidgets.QComboBox()
self.controls["lod_combo"].setObjectName("lodCombo")
# 右侧面板控件
# 模型操作组
self.controls["model_ops_group"] = QtWidgets.QGroupBox(LANG.get("model_operations", "模型操作"))
self.controls["model_ops_group"].setObjectName("modelOpsGroup")
# 模型操作按钮
self.buttons["pick_model"] = QtWidgets.QPushButton(LANG.get("pick_model", "拾取模型"))
self.buttons["load_model"] = QtWidgets.QPushButton(LANG.get("load_model", "加载模型"))
self.buttons["create_lod"] = QtWidgets.QPushButton(LANG.get("create_lod", "创建LOD"))
self.buttons["auto_load"] = QtWidgets.QPushButton(LANG.get("auto_load", "自动加载"))
# 模型工具组
self.controls["model_tools_group"] = QtWidgets.QGroupBox(LANG.get("model_tools", "模型工具"))
self.controls["model_tools_group"].setObjectName("modelToolsGroup")
# 模型工具按钮
self.buttons["standardize_names"] = QtWidgets.QPushButton(LANG.get("standardize_names", "标准化命名"))
self.buttons["auto_group"] = QtWidgets.QPushButton(LANG.get("auto_group", "自动分组"))
self.buttons["generate_accessories"] = QtWidgets.QPushButton(LANG.get("generate_accessories", "生成面部配件"))
self.buttons["fix_seams"] = QtWidgets.QPushButton(LANG.get("fix_seams", "修复接缝"))
self.buttons["fix_vertex_order"] = QtWidgets.QPushButton(LANG.get("fix_vertex_order", "修复点序"))
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建几何模型UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的geometry_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("geometry_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
main_layout = QtWidgets.QVBoxLayout(parent_tab)
main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4)
main_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 创建分割控件
splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 上部区域 - LOD选择和模型树
top_widget = QtWidgets.QWidget()
top_layout = QtWidgets.QVBoxLayout(top_widget)
top_layout.setContentsMargins(0, 0, 0, 0)
# LOD选择区域
lod_layout = QtWidgets.QHBoxLayout()
lod_layout.addWidget(QtWidgets.QLabel("LOD级别:"))
lod_layout.addWidget(lod_combo)
lod_layout.addStretch()
top_layout.addLayout(lod_layout)
# 模型树区域
model_group = QtWidgets.QGroupBox("模型列表")
model_layout = QtWidgets.QVBoxLayout(model_group)
model_layout.addWidget(model_tree)
top_layout.addWidget(model_group)
# 下部区域 - 模型信息
model_info_group = QtWidgets.QGroupBox("模型信息")
model_info_layout = QtWidgets.QVBoxLayout(model_info_group)
model_info_layout.addWidget(model_info_panel)
# 添加到分割控件
splitter.addWidget(top_widget)
splitter.addWidget(model_info_group)
# 按钮区域
button_layout = QtWidgets.QGridLayout()
button_layout.addWidget(model_buttons["load_model"], 0, 0)
button_layout.addWidget(model_buttons["create_lod"], 0, 1)
button_layout.addWidget(model_buttons["auto_load"], 1, 0)
button_layout.addWidget(model_buttons["standardize_name"], 1, 1)
button_layout.addWidget(model_buttons["auto_group"], 2, 0)
button_layout.addWidget(model_buttons["generate_accessories"], 2, 1)
button_layout.addWidget(model_buttons["fix_seams"], 3, 0)
button_layout.addWidget(model_buttons["fix_vertex_order"], 3, 1)
# 添加到主布局
main_layout.addWidget(splitter)
main_layout.addLayout(button_layout)
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建几何模型UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加主分割器
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 将左右面板添加到主分割器
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# 模型列表组布局
self.layouts["model_list_layout"] = QtWidgets.QVBoxLayout(self.controls["model_group"])
self.layouts["model_list_layout"].addWidget(self.controls["model_list"])
self.layouts["model_list_layout"].addWidget(self.buttons["refresh_models"])
# LOD过滤组布局
self.layouts["lod_filter_layout"] = QtWidgets.QHBoxLayout(self.controls["lod_filter_group"])
self.layouts["lod_filter_layout"].addWidget(self.controls["lod_label"])
self.layouts["lod_filter_layout"].addWidget(self.controls["lod_combo"])
# 添加组到左侧面板布局
self.layouts["left_layout"].addWidget(self.controls["model_group"])
self.layouts["left_layout"].addWidget(self.controls["lod_filter_group"])
self.layouts["left_layout"].addStretch()
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# 模型操作组布局
self.layouts["model_ops_layout"] = QtWidgets.QVBoxLayout(self.controls["model_ops_group"])
self.layouts["model_ops_layout"].addWidget(self.buttons["pick_model"])
self.layouts["model_ops_layout"].addWidget(self.buttons["load_model"])
self.layouts["model_ops_layout"].addWidget(self.buttons["create_lod"])
self.layouts["model_ops_layout"].addWidget(self.buttons["auto_load"])
# 模型工具组布局
self.layouts["model_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["model_tools_group"])
self.layouts["model_tools_layout"].addWidget(self.buttons["standardize_names"])
self.layouts["model_tools_layout"].addWidget(self.buttons["auto_group"])
self.layouts["model_tools_layout"].addWidget(self.buttons["generate_accessories"])
self.layouts["model_tools_layout"].addWidget(self.buttons["fix_seams"])
self.layouts["model_tools_layout"].addWidget(self.buttons["fix_vertex_order"])
# 添加组到右侧面板布局
self.layouts["right_layout"].addWidget(self.controls["model_ops_group"])
self.layouts["right_layout"].addWidget(self.controls["model_tools_group"])
self.layouts["right_layout"].addStretch()
# 创建分割器大小处理器
self.resize_handlers["main_splitter"] = ui_utils.SplitterResizeHandler(
self.main_widget, self.splitters["main_splitter"], is_horizontal=True
)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接几何模型UI信号和槽
"""
# 连接按钮点击事件到占位函数
model_buttons["load_model"].clicked.connect(lambda: print("加载模型功能待实现"))
model_buttons["create_lod"].clicked.connect(lambda: print("创建LOD功能待实现"))
model_buttons["auto_load"].clicked.connect(lambda: print("自动加载功能待实现"))
model_buttons["standardize_name"].clicked.connect(lambda: print("标准化命名功能待实现"))
model_buttons["auto_group"].clicked.connect(lambda: print("自动分组功能待实现"))
model_buttons["generate_accessories"].clicked.connect(lambda: print("生成面部配件功能待实现"))
model_buttons["fix_seams"].clicked.connect(lambda: print("修复接缝功能待实现"))
model_buttons["fix_vertex_order"].clicked.connect(lambda: print("修复点序功能待实现"))
# 连接LOD选择事件
lod_combo.currentIndexChanged.connect(lambda index: print(f"选择的LOD级别: {lod_combo.currentText()}"))
# 连接模型树选择事件
model_tree.itemSelectionChanged.connect(lambda: print("模型选择已更改"))
#===================================== PLACEHOLDER FUNCTION ===================================
def geometry_temp_function():
return utils_geometry.geometry_temp_utils_function()
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# 模型列表按钮连接
self.buttons["refresh_models"].clicked.connect(utils_geometry.geometry_temp_utils_function)
# LOD过滤连接
self.controls["lod_combo"].currentIndexChanged.connect(utils_geometry.geometry_temp_utils_function)
# 模型操作按钮连接
self.buttons["pick_model"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["load_model"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["create_lod"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["auto_load"].clicked.connect(utils_geometry.geometry_temp_utils_function)
# 模型工具按钮连接
self.buttons["standardize_names"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["auto_group"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["generate_accessories"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["fix_seams"].clicked.connect(utils_geometry.geometry_temp_utils_function)
self.buttons["fix_vertex_order"].clicked.connect(utils_geometry.geometry_temp_utils_function)

View File

@@ -13,135 +13,201 @@ Rigging UI Module for Plugin
- 创建绑定
- 复制蒙皮
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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 FUNCTIONS ===================================
from scripts.utils import utils_rigging as utils_rigging
from scripts.ui import ui_utils
from scripts.utils import utils_rigging
#========================================== 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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
dna_browser_tree = None
joint_list = None
dna_info_panel = None
rig_buttons = {}
class RiggingUI(ui_utils.BaseUI):
"""
绑定系统UI类 - 负责显示骨骼绑定编辑界面和基础操作
继承自BaseUI类实现绑定系统相关的UI功能
"""
#========================================== INIT ========================================
def __init__(self):
"""
初始化绑定系统UI
创建主控件和布局,并连接信号和槽
"""
super(RiggingUI, self).__init__()
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("riggingMainWidget")
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
def widgets():
"""
创建绑定系统UI控件
"""
global dna_browser_tree, joint_list, dna_info_panel, rig_buttons
# DNA浏览器树形视图
dna_browser_tree = QtWidgets.QTreeWidget()
dna_browser_tree.setHeaderLabels(["DNA文件", "版本", "修改日期"])
dna_browser_tree.setMinimumHeight(200)
# 关节列表
joint_list = QtWidgets.QListWidget()
joint_list.setMinimumHeight(150)
# DNA信息面板
dna_info_panel = QtWidgets.QTextEdit()
dna_info_panel.setReadOnly(True)
dna_info_panel.setMinimumHeight(100)
# 功能按钮
rig_buttons["load_dna"] = QtWidgets.QPushButton("加载DNA")
rig_buttons["import_joints"] = QtWidgets.QPushButton("导入骨骼")
rig_buttons["generate_body"] = QtWidgets.QPushButton("生成身体")
rig_buttons["calibrate_dna"] = QtWidgets.QPushButton("DNA校准")
rig_buttons["calibrate_joints"] = QtWidgets.QPushButton("骨骼位置校准")
rig_buttons["create_binding"] = QtWidgets.QPushButton("创建绑定")
rig_buttons["copy_skinning"] = QtWidgets.QPushButton("复制蒙皮")
rig_buttons["save_dna"] = QtWidgets.QPushButton("保存DNA")
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建绑定系统UI控件
包括按钮、标签、列表等
"""
# 标题标签
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("rigging_title", "骨骼绑定"))
self.controls["title_label"].setObjectName("riggingTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("riggingLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("riggingRightPanel")
# 左侧面板控件
# DNA浏览器组
self.controls["dna_browser_group"] = QtWidgets.QGroupBox(LANG.get("dna_browser", "DNA浏览器"))
self.controls["dna_browser_group"].setObjectName("dnaBrowserGroup")
# DNA浏览器列表
self.controls["dna_list"] = QtWidgets.QListWidget()
self.controls["dna_list"].setObjectName("dnaList")
# DNA浏览器刷新按钮
self.buttons["refresh_dna"] = QtWidgets.QPushButton(LANG.get("refresh", "刷新"))
self.buttons["refresh_dna"].setObjectName("refreshDnaButton")
# 右侧面板控件
# DNA操作组
self.controls["dna_ops_group"] = QtWidgets.QGroupBox(LANG.get("dna_operations", "DNA操作"))
self.controls["dna_ops_group"].setObjectName("dnaOpsGroup")
# DNA操作按钮
self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼"))
self.buttons["generate_body"] = QtWidgets.QPushButton(LANG.get("generate_body", "生成身体"))
self.buttons["calibrate_dna"] = QtWidgets.QPushButton(LANG.get("calibrate_dna", "DNA校准"))
# 骨骼操作组
self.controls["skeleton_ops_group"] = QtWidgets.QGroupBox(LANG.get("skeleton_operations", "骨骼操作"))
self.controls["skeleton_ops_group"].setObjectName("skeletonOpsGroup")
# 骨骼操作按钮
self.buttons["calibrate_skeleton"] = QtWidgets.QPushButton(LANG.get("calibrate_skeleton", "骨骼位置校准"))
self.buttons["create_binding"] = QtWidgets.QPushButton(LANG.get("create_binding", "创建绑定"))
self.buttons["copy_skin"] = QtWidgets.QPushButton(LANG.get("copy_skin", "复制蒙皮"))
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建绑定系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的rigging_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("rigging_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建分割控件
splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 上部区域 - DNA浏览器
dna_browser_group = QtWidgets.QGroupBox("DNA浏览器")
dna_browser_layout = QtWidgets.QVBoxLayout(dna_browser_group)
dna_browser_layout.addWidget(dna_browser_tree)
# 中部区域 - 关节列表
joint_list_group = QtWidgets.QGroupBox("骨骼列表")
joint_list_layout = QtWidgets.QVBoxLayout(joint_list_group)
joint_list_layout.addWidget(joint_list)
# 下部区域 - DNA信息
dna_info_group = QtWidgets.QGroupBox("DNA信息")
dna_info_layout = QtWidgets.QVBoxLayout(dna_info_group)
dna_info_layout.addWidget(dna_info_panel)
# 添加到分割控件
splitter.addWidget(dna_browser_group)
splitter.addWidget(joint_list_group)
splitter.addWidget(dna_info_group)
# 按钮区域
button_layout = QtWidgets.QGridLayout()
button_layout.addWidget(rig_buttons["load_dna"], 0, 0)
button_layout.addWidget(rig_buttons["import_joints"], 0, 1)
button_layout.addWidget(rig_buttons["generate_body"], 1, 0)
button_layout.addWidget(rig_buttons["calibrate_dna"], 1, 1)
button_layout.addWidget(rig_buttons["calibrate_joints"], 2, 0)
button_layout.addWidget(rig_buttons["create_binding"], 2, 1)
button_layout.addWidget(rig_buttons["copy_skinning"], 3, 0)
button_layout.addWidget(rig_buttons["save_dna"], 3, 1)
# 添加到主布局
main_layout.addWidget(splitter)
main_layout.addLayout(button_layout)
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建绑定系统UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加主分割器
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 将左右面板添加到主分割器
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# DNA浏览器组布局
self.layouts["dna_browser_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_browser_group"])
self.layouts["dna_browser_layout"].addWidget(self.controls["dna_list"])
self.layouts["dna_browser_layout"].addWidget(self.buttons["refresh_dna"])
# 添加组到左侧面板布局
self.layouts["left_layout"].addWidget(self.controls["dna_browser_group"])
self.layouts["left_layout"].addStretch()
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# DNA操作组布局
self.layouts["dna_ops_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_ops_group"])
self.layouts["dna_ops_layout"].addWidget(self.buttons["import_skeleton"])
self.layouts["dna_ops_layout"].addWidget(self.buttons["generate_body"])
self.layouts["dna_ops_layout"].addWidget(self.buttons["calibrate_dna"])
# 骨骼操作组布局
self.layouts["skeleton_ops_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_ops_group"])
self.layouts["skeleton_ops_layout"].addWidget(self.buttons["calibrate_skeleton"])
self.layouts["skeleton_ops_layout"].addWidget(self.buttons["create_binding"])
self.layouts["skeleton_ops_layout"].addWidget(self.buttons["copy_skin"])
# 添加组到右侧面板布局
self.layouts["right_layout"].addWidget(self.controls["dna_ops_group"])
self.layouts["right_layout"].addWidget(self.controls["skeleton_ops_group"])
self.layouts["right_layout"].addStretch()
# 创建分割器大小处理器
self.resize_handlers["main_splitter"] = ui_utils.SplitterResizeHandler(
self.main_widget, self.splitters["main_splitter"], is_horizontal=True
)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接绑定系统UI信号和槽
"""
# 连接按钮点击事件到占位函数
rig_buttons["load_dna"].clicked.connect(lambda: print("加载DNA功能待实现"))
rig_buttons["import_joints"].clicked.connect(lambda: print("导入骨骼功能待实现"))
rig_buttons["generate_body"].clicked.connect(lambda: print("生成身体功能待实现"))
rig_buttons["calibrate_dna"].clicked.connect(lambda: print("DNA校准功能待实现"))
rig_buttons["calibrate_joints"].clicked.connect(lambda: print("骨骼位置校准功能待实现"))
rig_buttons["create_binding"].clicked.connect(lambda: print("创建绑定功能待实现"))
rig_buttons["copy_skinning"].clicked.connect(lambda: print("复制蒙皮功能待实现"))
rig_buttons["save_dna"].clicked.connect(lambda: print("保存DNA功能待实现"))
# 连接树形视图选择事件
dna_browser_tree.itemSelectionChanged.connect(lambda: print("DNA文件选择已更改"))
# 连接关节列表选择事件
joint_list.itemSelectionChanged.connect(lambda: print("骨骼选择已更改"))
#===================================== PLACEHOLDER FUNCTION ===================================
def rigging_temp_function():
return utils_rigging.rigging_temp_utils_function()
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# DNA浏览器按钮连接
self.buttons["refresh_dna"].clicked.connect(utils_rigging.rigging_temp_utils_function)
# DNA操作按钮连接
self.buttons["import_skeleton"].clicked.connect(utils_rigging.rigging_temp_utils_function)
self.buttons["generate_body"].clicked.connect(utils_rigging.rigging_temp_utils_function)
self.buttons["calibrate_dna"].clicked.connect(utils_rigging.rigging_temp_utils_function)
# 骨骼操作按钮连接
self.buttons["calibrate_skeleton"].clicked.connect(utils_rigging.rigging_temp_utils_function)
self.buttons["create_binding"].clicked.connect(utils_rigging.rigging_temp_utils_function)
self.buttons["copy_skin"].clicked.connect(utils_rigging.rigging_temp_utils_function)

View File

@@ -1,119 +1,262 @@
/* Plugin 统一样式表 */
/* MetaFusion 插件样式表 */
/* 作者: CGNICO */
/* 版本: Alpha v1.0.0 */
/* 全局样式 */
/* ==================== 全局样式 ==================== */
QWidget {
font-family: "Microsoft YaHei", "SimHei", sans-serif;
font-size: 9pt;
font-family: "Microsoft YaHei", "SimHei", "Arial", sans-serif;
font-size: 12px;
color: #E0E0E0;
background-color: #333333;
}
/* 菜单样式 */
QMenuBar {
background-color: #2D2D30;
}
QLabel {
color: #E0E0E0;
}
QMenuBar::item {
background-color: transparent;
padding: 5px 10px;
QLabel#mainTitleLabel {
font-size: 16px;
font-weight: bold;
color: #FFFFFF;
padding: 5px;
}
QMenuBar::item:selected {
background-color: #007ACC;
color: white;
}
QMenu {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
}
QMenu::item {
padding: 5px 30px 5px 20px;
}
QMenu::item:selected {
background-color: #007ACC;
color: white;
}
/* 工具栏样式 */
QToolBar {
background-color: #2D2D30;
border: 1px solid #3F3F46;
spacing: 3px;
}
QToolBar::separator {
background-color: #3F3F46;
width: 1px;
height: 20px;
}
/* 工具栏图标按钮样式 */
QPushButton#ToolbarIconButton {
background-color: #333333;
border: none;
padding: 1px;
min-width: 24px;
max-width: 24px;
min-height: 24px;
max-height: 24px;
}
QPushButton#ToolbarIconButton:hover {
background-color: #444444;
}
QPushButton#ToolbarIconButton:pressed {
background-color: #555555;
}
/* 工具栏分隔符样式 */
QFrame#ToolbarSeparator {
background-color: #555555;
max-width: 1px;
min-width: 1px;
}
/* 工具栏状态标签样式 */
QLabel#StatusLabel {
color: #CCCCCC;
padding-right: 5px;
font-size: 9pt;
}
/* 标签页样式 */
/* ==================== 标签页样式 ==================== */
QTabWidget::pane {
border: 1px solid #3F3F46;
border: 1px solid #1E1E1E;
background-color: #2D2D30;
border-radius: 3px;
}
QTabBar::tab {
background-color: #252526;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-bottom: none;
padding: 5px 10px;
background-color: #3E3E42;
color: #CCCCCC;
padding: 8px 15px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
min-width: 80px;
border: 1px solid #1E1E1E;
border-bottom: none;
margin-right: 2px;
}
QTabBar::tab:selected {
background-color: #007ACC;
color: white;
color: #FFFFFF;
}
QTabBar::tab:hover:!selected {
background-color: #3E3E40;
background-color: #505050;
}
/* 分组框样式 */
/* ==================== 按钮样式 ==================== */
QPushButton {
background-color: #3E3E42;
color: #CCCCCC;
border: 1px solid #1E1E1E;
border-radius: 3px;
padding: 5px 10px;
min-height: 25px;
}
QPushButton:hover {
background-color: #505050;
border: 1px solid #007ACC;
}
QPushButton:pressed {
background-color: #007ACC;
color: #FFFFFF;
}
QPushButton:disabled {
background-color: #2D2D30;
color: #656565;
border: 1px solid #1E1E1E;
}
/* 主要操作按钮 */
QPushButton.primary {
background-color: #007ACC;
color: #FFFFFF;
}
QPushButton.primary:hover {
background-color: #1C97EA;
}
QPushButton.primary:pressed {
background-color: #0062A3;
}
/* 危险操作按钮 */
QPushButton.danger {
background-color: #E51400;
color: #FFFFFF;
}
QPushButton.danger:hover {
background-color: #FF2D1C;
}
QPushButton.danger:pressed {
background-color: #B30F00;
}
/* ==================== 输入框样式 ==================== */
QLineEdit, QTextEdit, QPlainTextEdit {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
border-radius: 3px;
padding: 3px;
selection-background-color: #264F78;
}
QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {
border: 1px solid #007ACC;
}
QLineEdit:disabled, QTextEdit:disabled, QPlainTextEdit:disabled {
background-color: #2D2D30;
color: #656565;
border: 1px solid #1E1E1E;
}
/* ==================== 下拉框样式 ==================== */
QComboBox {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
border-radius: 3px;
padding: 3px 18px 3px 3px;
min-height: 25px;
}
QComboBox:hover {
border: 1px solid #007ACC;
}
QComboBox:on {
background-color: #3E3E42;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left: 1px solid #3E3E42;
}
QComboBox::down-arrow {
image: url(":/icons/dropdown_arrow.png");
width: 10px;
height: 10px;
}
QComboBox QAbstractItemView {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
selection-background-color: #007ACC;
selection-color: #FFFFFF;
outline: 0;
}
/* ==================== 列表控件样式 ==================== */
QListWidget, QTreeWidget, QTableWidget {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
border-radius: 3px;
alternate-background-color: #2A2A2A;
outline: 0;
}
QListWidget::item, QTreeWidget::item, QTableWidget::item {
padding: 3px;
}
QListWidget::item:selected, QTreeWidget::item:selected, QTableWidget::item:selected {
background-color: #007ACC;
color: #FFFFFF;
}
QListWidget::item:hover, QTreeWidget::item:hover, QTableWidget::item:hover {
background-color: #3E3E42;
}
/* ==================== 滚动条样式 ==================== */
QScrollBar:vertical {
background-color: #2D2D30;
width: 12px;
margin: 12px 0 12px 0;
border: 1px solid #1E1E1E;
border-radius: 3px;
}
QScrollBar::handle:vertical {
background-color: #3E3E42;
min-height: 20px;
border-radius: 3px;
}
QScrollBar::handle:vertical:hover {
background-color: #505050;
}
QScrollBar::add-line:vertical {
border: none;
background: none;
height: 10px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
border: none;
background: none;
height: 10px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar:horizontal {
background-color: #2D2D30;
height: 12px;
margin: 0 12px 0 12px;
border: 1px solid #1E1E1E;
border-radius: 3px;
}
QScrollBar::handle:horizontal {
background-color: #3E3E42;
min-width: 20px;
border-radius: 3px;
}
QScrollBar::handle:horizontal:hover {
background-color: #505050;
}
QScrollBar::add-line:horizontal {
border: none;
background: none;
width: 10px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
border: none;
background: none;
width: 10px;
subcontrol-position: left;
subcontrol-origin: margin;
}
/* ==================== 分组框样式 ==================== */
QGroupBox {
border: 1px solid #3F3F46;
border: 1px solid #3E3E42;
border-radius: 3px;
margin-top: 10px;
padding-top: 10px;
@@ -124,232 +267,252 @@ QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 5px;
color: #E0E0E0;
color: #007ACC;
}
/* 下拉框样式 */
QComboBox {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-radius: 3px;
padding: 3px 18px 3px 3px;
min-width: 6em;
/* ==================== 分割器样式 ==================== */
QSplitter::handle {
background-color: #3E3E42;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left: 1px solid #3F3F46;
QSplitter::handle:horizontal {
width: 2px;
}
QComboBox QAbstractItemView {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
selection-background-color: #264F78;
selection-color: white;
QSplitter::handle:vertical {
height: 2px;
}
/* 按钮样式 */
QPushButton {
background-color: #0E639C;
color: white;
border: 1px solid #0E639C;
border-radius: 3px;
padding: 5px 10px;
min-width: 80px;
QSplitter::handle:hover {
background-color: #007ACC;
}
QPushButton:hover {
background-color: #1177BB;
border: 1px solid #1177BB;
}
QPushButton:pressed {
background-color: #00578A;
border: 1px solid #00578A;
}
QPushButton:disabled {
background-color: #3F3F46;
color: #9D9D9D;
border: 1px solid #3F3F46;
}
/* 输入框样式 */
QLineEdit, QTextEdit, QPlainTextEdit {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-radius: 3px;
padding: 3px;
selection-background-color: #264F78;
}
/* 单选框样式 */
QRadioButton {
color: #E0E0E0;
spacing: 5px;
}
QRadioButton::indicator {
width: 13px;
height: 13px;
}
/* 复选框样式 */
QCheckBox {
color: #E0E0E0;
spacing: 5px;
}
QCheckBox::indicator {
width: 13px;
height: 13px;
}
/* 滑块样式 */
/* ==================== 滑块样式 ==================== */
QSlider::groove:horizontal {
border: 1px solid #3F3F46;
height: 8px;
background: #1E1E1E;
margin: 2px 0;
border-radius: 4px;
border: 1px solid #1E1E1E;
height: 4px;
background: #3E3E42;
margin: 0 5px;
border-radius: 2px;
}
QSlider::handle:horizontal {
background: #007ACC;
border: 1px solid #007ACC;
width: 14px;
height: 14px;
margin: -4px 0;
border-radius: 7px;
border: 1px solid #005F9E;
width: 12px;
height: 12px;
margin: -5px 0;
border-radius: 6px;
}
QSlider::handle:horizontal:hover {
background: #1177BB;
border: 1px solid #1177BB;
background: #1C97EA;
border: 1px solid #007ACC;
}
/* 进度条样式 */
QSlider::sub-page:horizontal {
background: #007ACC;
border-radius: 2px;
}
/* ==================== 复选框样式 ==================== */
QCheckBox {
spacing: 5px;
}
QCheckBox::indicator {
width: 15px;
height: 15px;
}
QCheckBox::indicator:unchecked {
border: 1px solid #3E3E42;
background-color: #1E1E1E;
border-radius: 2px;
}
QCheckBox::indicator:unchecked:hover {
border: 1px solid #007ACC;
}
QCheckBox::indicator:checked {
border: 1px solid #007ACC;
background-color: #007ACC;
border-radius: 2px;
image: url(":/icons/checkmark.png");
}
/* ==================== 单选框样式 ==================== */
QRadioButton {
spacing: 5px;
}
QRadioButton::indicator {
width: 15px;
height: 15px;
}
QRadioButton::indicator:unchecked {
border: 1px solid #3E3E42;
background-color: #1E1E1E;
border-radius: 7px;
}
QRadioButton::indicator:unchecked:hover {
border: 1px solid #007ACC;
}
QRadioButton::indicator:checked {
border: 1px solid #007ACC;
background-color: #1E1E1E;
border-radius: 7px;
}
QRadioButton::indicator:checked::before {
content: "";
display: block;
width: 7px;
height: 7px;
background-color: #007ACC;
border-radius: 4px;
margin: 3px;
}
/* ==================== 进度条样式 ==================== */
QProgressBar {
border: 1px solid #3F3F46;
border: 1px solid #3E3E42;
border-radius: 3px;
background-color: #1E1E1E;
text-align: center;
color: white;
color: #E0E0E0;
}
QProgressBar::chunk {
background-color: #007ACC;
width: 10px;
margin: 0.5px;
}
/* 列表和树视图样式 */
QTreeView, QListView, QTableView {
background-color: #1E1E1E;
alternate-background-color: #262626;
/* ==================== 菜单样式 ==================== */
QMenuBar {
background-color: #2D2D30;
color: #E0E0E0;
border: 1px solid #3F3F46;
selection-background-color: #264F78;
selection-color: white;
outline: none;
border-bottom: 1px solid #1E1E1E;
}
QTreeView::item, QListView::item, QTableView::item {
QMenuBar::item {
background: transparent;
padding: 5px 10px;
}
QMenuBar::item:selected {
background-color: #3E3E42;
color: #FFFFFF;
}
QMenuBar::item:pressed {
background-color: #007ACC;
color: #FFFFFF;
}
QMenu {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
}
QMenu::item {
padding: 5px 30px 5px 20px;
}
QMenu::item:selected {
background-color: #007ACC;
color: #FFFFFF;
}
QMenu::separator {
height: 1px;
background-color: #3E3E42;
margin: 5px 0;
}
/* ==================== 工具提示样式 ==================== */
QToolTip {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
padding: 3px;
}
QTreeView::item:selected, QListView::item:selected, QTableView::item:selected {
background-color: #264F78;
color: white;
}
QTreeView::item:hover, QListView::item:hover, QTableView::item:hover {
background-color: #2A2D2E;
}
QHeaderView::section {
background-color: #252526;
color: #E0E0E0;
padding: 3px;
border: 1px solid #3F3F46;
}
/* 滚动条样式 */
QScrollBar:vertical {
background-color: #1E1E1E;
width: 14px;
margin: 14px 0 14px 0;
border: 1px solid #3F3F46;
}
QScrollBar::handle:vertical {
background-color: #3E3E42;
min-height: 20px;
}
QScrollBar::add-line:vertical {
border: 1px solid #3F3F46;
background-color: #3E3E42;
height: 14px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
border: 1px solid #3F3F46;
background-color: #3E3E42;
height: 14px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar:horizontal {
background-color: #1E1E1E;
height: 14px;
margin: 0 14px 0 14px;
border: 1px solid #3F3F46;
}
QScrollBar::handle:horizontal {
background-color: #3E3E42;
min-width: 20px;
}
QScrollBar::add-line:horizontal {
border: 1px solid #3F3F46;
background-color: #3E3E42;
width: 14px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
border: 1px solid #3F3F46;
background-color: #3E3E42;
width: 14px;
subcontrol-position: left;
subcontrol-origin: margin;
}
/* 状态栏样式 */
/* ==================== 状态栏样式 ==================== */
QStatusBar {
background-color: #333333;
background-color: #2D2D30;
color: #E0E0E0;
border-top: 1px solid #3F3F46;
border-top: 1px solid #1E1E1E;
}
QStatusBar::item {
border: none;
}
/* 提示框样式 */
QToolTip {
background-color: #2D2D30;
color: #E0E0E0;
border: 1px solid #3F3F46;
padding: 3px;
/* ==================== 特定控件样式 ==================== */
/* 标题标签 */
QLabel[objectName="titleLabel"],
QLabel[objectName="toolbarTitleLabel"],
QLabel[objectName="definitionTitleLabel"],
QLabel[objectName="geometryTitleLabel"],
QLabel[objectName="riggingTitleLabel"],
QLabel[objectName="behaviourTitleLabel"] {
font-size: 14px;
font-weight: bold;
color: #007ACC;
padding: 5px;
background-color: #252526;
border-bottom: 1px solid #3E3E42;
}
/* 底部滑块 */
QSlider#bottomSlider {
margin: 10px 0;
}
/* 底部标签页按钮 */
QPushButton[objectName*="tabButton"] {
background-color: #3E3E42;
color: #CCCCCC;
border: 1px solid #1E1E1E;
border-radius: 3px;
padding: 5px;
min-width: 40px;
min-height: 25px;
}
QPushButton[objectName*="tabButton"]:checked,
QPushButton[objectName*="tabButton"]:pressed {
background-color: #007ACC;
color: #FFFFFF;
}
QPushButton[objectName*="tabButton"]:hover:!checked {
background-color: #505050;
border: 1px solid #007ACC;
}
/* 搜索框 */
QLineEdit[objectName*="searchInput"],
QLineEdit[objectName*="filterInput"] {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3E3E42;
border-radius: 3px;
padding: 5px 25px 5px 5px;
background-image: url(":/icons/search.png");
background-repeat: no-repeat;
background-position: right center;
background-origin: content;
}
QLineEdit[objectName*="searchInput"]:focus,
QLineEdit[objectName*="filterInput"]:focus {
border: 1px solid #007ACC;
}

View File

@@ -12,185 +12,165 @@ Toolbar UI Module for Plugin
- 创建RL4节点用于切换DNA编辑的状态
- 删除RL4节点用于切换DNA编辑的状态
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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 FUNCTIONS ===================================
from scripts.utils import utils_toolbar as utils_toolbar
from scripts.ui import ui_utils
from scripts.utils import utils_toolbar
#========================================== 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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
toolbar_buttons = {}
status_label = None
# 按钮图标和提示文本映射
button_configs = {
"open_file": {"icon": "open.png", "tooltip": "打开文件"},
"save_file": {"icon": "save.png", "tooltip": "保存文件"},
"save_as": {"icon": "save_new.png", "tooltip": "另存为"},
"load_preset": {"icon": "import_preset.png", "tooltip": "加载预设"},
"save_preset": {"icon": "export_preset.png", "tooltip": "导出预设"},
"import_dna": {"icon": "import_dna.png", "tooltip": "导入DNA"},
"export_dna": {"icon": "export_dna.png", "tooltip": "导出DNA"},
"create_rl4": {"icon": "create_rl4_node.png", "tooltip": "创建RL4节点"},
"delete_rl4": {"icon": "delete_rl4_node.png", "tooltip": "删除RL4节点"}
}
def widgets():
class ToolbarUI(ui_utils.BaseUI):
"""
创建工具栏UI控件
工具栏UI类 - 负责显示工具栏界面和基础操作
继承自BaseUI类实现工具栏相关的UI功能
"""
global toolbar_buttons, status_label
# 创建按钮的辅助函数
def create_icon_button(button_id, size=24):
config = button_configs[button_id]
button = QtWidgets.QPushButton()
button.setToolTip(config["tooltip"]) # 设置提示文本
button.setFixedSize(size, size) # 设置固定大小
# 设置样式类名
button.setObjectName("ToolbarIconButton")
#========================================== INIT ========================================
def __init__(self):
"""
初始化工具栏UI
创建主控件和布局,并连接信号和槽
"""
super(ToolbarUI, self).__init__()
# 设置图标
icon_path = os.path.abspath(os.path.join(ICONS_PATH, config["icon"]))
if os.path.exists(icon_path):
icon = QtGui.QIcon(icon_path)
if not icon.isNull():
button.setIcon(icon)
button.setIconSize(QtCore.QSize(size-4, size-4)) # 图标尺寸稍小于按钮
print(f"成功设置按钮图标 {button_id}: {icon_path}")
else:
print(f"图标加载失败 {button_id}: {icon_path}")
else:
print(f"警告: 图标文件未找到 {button_id}: {icon_path}")
return button
# 创建所有按钮
# 文件操作按钮
toolbar_buttons["open_file"] = create_icon_button("open_file")
toolbar_buttons["save_file"] = create_icon_button("save_file")
toolbar_buttons["save_as"] = create_icon_button("save_as")
# 预设操作按钮
toolbar_buttons["load_preset"] = create_icon_button("load_preset")
toolbar_buttons["save_preset"] = create_icon_button("save_preset")
# DNA操作按钮
toolbar_buttons["import_dna"] = create_icon_button("import_dna")
toolbar_buttons["export_dna"] = create_icon_button("export_dna")
# RL4节点操作按钮
toolbar_buttons["create_rl4"] = create_icon_button("create_rl4")
toolbar_buttons["delete_rl4"] = create_icon_button("delete_rl4")
# 移除DNA下拉菜单
# 状态标签
status_label = QtWidgets.QLabel("就绪")
status_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
status_label.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
status_label.setObjectName("StatusLabel")
# status_label.setStyleSheet("""
# QLabel {
# color: #CCCCCC;
# padding-right: 5px;
# font-size: 9pt;
# }
# """)
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("toolbarMainWidget")
# 初始化UI
self.create_widgets()
self.create_layouts()
self.create_connections()
#========================================== LAYOUTS ==========================================
def layouts(parent_frame=None):
"""
创建工具栏UI布局
Args:
parent_frame: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的toolbar_frame
if not parent_frame:
parent_frame = ui_utils.get_parent_widget("toolbar_frame")
if not parent_frame:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_frame.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建工具栏布局
toolbar_layout = QtWidgets.QHBoxLayout()
toolbar_layout.setContentsMargins(2, 2, 2, 2)
toolbar_layout.setSpacing(2) # 减小按钮之间的间距
toolbar_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 创建分隔符样式
def create_separator():
separator = QtWidgets.QFrame()
separator.setFrameShape(QtWidgets.QFrame.VLine)
separator.setFrameShadow(QtWidgets.QFrame.Sunken)
separator.setObjectName("ToolbarSeparator")
return separator
# 添加文件操作按钮
toolbar_layout.addWidget(toolbar_buttons["open_file"])
toolbar_layout.addWidget(toolbar_buttons["save_file"])
toolbar_layout.addWidget(toolbar_buttons["save_as"])
toolbar_layout.addWidget(create_separator()) # 使用自定义分隔符
# 添加预设操作按钮
toolbar_layout.addWidget(toolbar_buttons["load_preset"])
toolbar_layout.addWidget(toolbar_buttons["save_preset"])
toolbar_layout.addWidget(create_separator()) # 使用自定义分隔符
# 添加DNA操作按钮
toolbar_layout.addWidget(toolbar_buttons["import_dna"])
toolbar_layout.addWidget(toolbar_buttons["export_dna"])
toolbar_layout.addWidget(create_separator()) # 使用自定义分隔符
# 添加RL4节点操作按钮
toolbar_layout.addWidget(toolbar_buttons["create_rl4"])
toolbar_layout.addWidget(toolbar_buttons["delete_rl4"])
toolbar_layout.addStretch()
toolbar_layout.addWidget(status_label)
# 添加到主布局
main_layout.addLayout(toolbar_layout)
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建工具栏UI控件
包括按钮、标签、输入框等
"""
# 标题标签
self.controls["title_label"] = QtWidgets.QLabel(LANG.get("toolbar_title", "工具栏"))
self.controls["title_label"].setObjectName("toolbarTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
# 预设组
self.controls["preset_group"] = QtWidgets.QGroupBox(LANG.get("preset_group", "预设"))
self.controls["preset_group"].setObjectName("presetGroup")
# 预设标签和下拉框
self.controls["preset_label"] = QtWidgets.QLabel(LANG.get("preset", "预设:"))
self.controls["preset_combo"] = QtWidgets.QComboBox()
self.controls["preset_combo"].setObjectName("presetCombo")
# 预设按钮
self.buttons["load_preset"] = QtWidgets.QPushButton(LANG.get("load_preset", "加载预设"))
self.buttons["save_preset"] = QtWidgets.QPushButton(LANG.get("save_preset", "保存预设"))
# DNA操作组
self.controls["dna_group"] = QtWidgets.QGroupBox(LANG.get("dna_operations", "DNA操作"))
self.controls["dna_group"].setObjectName("dnaGroup")
# DNA操作按钮
self.buttons["import_dna"] = QtWidgets.QPushButton(LANG.get("import_dna", "导入DNA"))
self.buttons["export_dna"] = QtWidgets.QPushButton(LANG.get("export_dna", "导出DNA"))
self.buttons["create_rl4"] = QtWidgets.QPushButton(LANG.get("create_rl4", "创建RL4节点"))
self.buttons["delete_rl4"] = QtWidgets.QPushButton(LANG.get("delete_rl4", "删除RL4节点"))
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接工具栏UI信号和槽
"""
# 文件操作按钮连接
toolbar_buttons["open_file"].clicked.connect(lambda: print("打开文件功能待实现"))
toolbar_buttons["save_file"].clicked.connect(lambda: print("保存文件功能待实现"))
toolbar_buttons["save_as"].clicked.connect(lambda: print("另存为功能待实现"))
# 预设操作按钮连接
toolbar_buttons["load_preset"].clicked.connect(lambda: print("加载预设功能待实现"))
toolbar_buttons["save_preset"].clicked.connect(lambda: print("导出预设功能待实现"))
# DNA操作按钮连接
toolbar_buttons["import_dna"].clicked.connect(lambda: print("导入DNA功能待实现"))
toolbar_buttons["export_dna"].clicked.connect(lambda: print("导出DNA功能待实现"))
# RL4节点操作按钮连接
toolbar_buttons["create_rl4"].clicked.connect(lambda: print("创建RL4节点功能待实现"))
toolbar_buttons["delete_rl4"].clicked.connect(lambda: print("删除RL4节点功能待实现"))
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建工具栏UI布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 预设组布局
self.layouts["preset_layout"] = QtWidgets.QVBoxLayout(self.controls["preset_group"])
# 预设选择布局
self.layouts["preset_select_layout"] = QtWidgets.QHBoxLayout()
self.layouts["preset_select_layout"].addWidget(self.controls["preset_label"])
self.layouts["preset_select_layout"].addWidget(self.controls["preset_combo"])
# 预设按钮布局
self.layouts["preset_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["preset_buttons_layout"].addWidget(self.buttons["load_preset"])
self.layouts["preset_buttons_layout"].addWidget(self.buttons["save_preset"])
# 添加到预设组布局
self.layouts["preset_layout"].addLayout(self.layouts["preset_select_layout"])
self.layouts["preset_layout"].addLayout(self.layouts["preset_buttons_layout"])
# DNA操作组布局
self.layouts["dna_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_group"])
# DNA操作按钮布局
self.layouts["dna_buttons_layout"] = QtWidgets.QGridLayout()
self.layouts["dna_buttons_layout"].addWidget(self.buttons["import_dna"], 0, 0)
self.layouts["dna_buttons_layout"].addWidget(self.buttons["export_dna"], 0, 1)
self.layouts["dna_buttons_layout"].addWidget(self.buttons["create_rl4"], 1, 0)
self.layouts["dna_buttons_layout"].addWidget(self.buttons["delete_rl4"], 1, 1)
# 添加到DNA操作组布局
self.layouts["dna_layout"].addLayout(self.layouts["dna_buttons_layout"])
# 添加组到主布局
self.layouts["main_layout"].addWidget(self.controls["preset_group"])
self.layouts["main_layout"].addWidget(self.controls["dna_group"])
self.layouts["main_layout"].addStretch()
#===================================== PLACEHOLDER FUNCTION ===================================
def toolbar_temp_function():
return utils_toolbar.toolbar_temp_utils_function()
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# 预设按钮连接
self.buttons["load_preset"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)
self.buttons["save_preset"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)
# DNA操作按钮连接
self.buttons["import_dna"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)
self.buttons["export_dna"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)
self.buttons["create_rl4"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)
self.buttons["delete_rl4"].clicked.connect(utils_toolbar.toolbar_temp_utils_function)

View File

@@ -5,17 +5,108 @@
UI Utilities Module for Plugin
UI工具模块 - 提供UI相关的通用函数
"""
#===================================== IMPORT MODULES =====================================
#========================================= IMPORT =========================================
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
#========================================== CONFIG ========================================
import config
#===================================== UI UTILITY FUNCTIONS ===================================
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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
TOOL_NAME = config.TOOL_NAME
#============================================ INIT ==========================================
# 定义窗口大小变化事件处理类
# 用于监听窗口大小变化并调整分割器宽度
class SplitterResizeHandler(QtCore.QObject):
def __init__(self, parent_tab, main_splitter, is_horizontal=True):
super(SplitterResizeHandler, self).__init__(parent_tab)
self.parent_tab = parent_tab
self.main_splitter = main_splitter
self.is_horizontal = is_horizontal # 是否为水平分割器
# 安装事件过滤器到父标签页
self.parent_tab.installEventFilter(self)
def eventFilter(self, obj, event):
# 监听大小变化事件
if obj == self.parent_tab and event.type() == QtCore.QEvent.Resize:
# 当窗口大小变化时,调整分割器宽度
self.adjustSplitterSizes()
return super(SplitterResizeHandler, self).eventFilter(obj, event)
def adjustSplitterSizes(self):
# 确保分割器存在且父标签页可见
if self.main_splitter and self.parent_tab.isVisible():
if self.is_horizontal:
# 获取父标签页当前宽度
width = self.parent_tab.width()
# 设置分割器左右宽度均等
self.main_splitter.setSizes([width // 2, width // 2])
print(f"分割器 - 窗口大小变化,调整水平分割器宽度为: {width // 2}, {width // 2}")
else:
# 获取父标签页当前高度
height = self.parent_tab.height()
# 设置分割器上下比例为3:1
self.main_splitter.setSizes([height * 3 // 4, height // 4])
print(f"分割器 - 窗口大小变化,调整垂直分割器高度为: {height * 3 // 4}, {height // 4}")
# 使用类来管理UI控件避免全局变量
class BaseUI:
"""
基础UI类 - 管理所有UI控件
使用字典存储控件、按钮、布局和分割器引用,避免全局变量
"""
def __init__(self):
# UI控件字典
self.controls = {}
# 按钮字典
self.buttons = {}
# 布局字典
self.layouts = {}
# 分割器字典
self.splitters = {}
# 分割器大小处理器字典
self.resize_handlers = {}
def get_maya_main_window():
"""
获取Maya主窗口
Returns:
QWidget: Maya主窗口控件
"""
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
def get_parent_widget(widget_name):
"""
@@ -49,14 +140,4 @@ def get_parent_widget(widget_name):
return child
print(f"无法找到控件: {widget_name}")
return None
def get_maya_main_window():
"""
获取Maya主窗口
Returns:
QWidget: Maya主窗口控件
"""
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
return None

View File

@@ -3,11 +3,13 @@
"""
Behaviour function module
行为系统工具函数模块 - 提供行为系统UI所需的所有功能函数
"""
#===================================== IMPORT MODULES =====================================
import maya.cmds as cmds
import pymel.core as pm
from Qt import QtWidgets, QtCore, QtGui
import importlib
import sys
import os
@@ -19,5 +21,4 @@ def behaviour_temp_utils_function():
Placeholder function for behaviour module
This function will be replaced with actual functionality in future updates
"""
print("Behaviour module initialized with placeholder function")
return True
print("Behaviour module temporary function called")

View File

@@ -3,6 +3,7 @@
"""
Definition function module
定义统工具函数模块 - 提供定义统UI所需的所有功能函数
"""
#===================================== IMPORT MODULES =====================================
@@ -19,5 +20,4 @@ def definition_temp_utils_function():
Placeholder function for definition module
This function will be replaced with actual functionality in future updates
"""
print("Definition module initialized with placeholder function")
return True
print("Definition module temporary function called")