#!/usr/bin/env python # -*- coding: utf-8 -*- """ Rigging UI Module for Plugin 绑定系统UI模块 - 负责显示骨骼绑定编辑界面和基础操作 基本功能: - DNA浏览器 - 根据DNA导入骨骼 - 根据DNA生成身体 - DNA校准 - 骨骼位置校准 - 创建绑定 - 复制蒙皮 """ #========================================= 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 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 TOOL_WIDTH = config.TOOL_WIDTH TOOL_HEIGHT = config.TOOL_HEIGHT #========================================= LOCATION ======================================= from scripts.ui import localization LANG = localization.LANG class RiggingUI(ui_utils.BaseUI): """ 绑定系统UI类 - 负责显示骨骼绑定编辑界面和基础操作 继承自BaseUI类,实现绑定系统相关的UI功能 """ #========================================== INIT ======================================== def __init__(self): """ 初始化绑定系统UI 创建主控件和布局,并连接信号和槽 """ super(RiggingUI, self).__init__() # 初始化字典 self.controls = {} self.layouts = {} self.buttons = {} self.splitters = {} self.inputs = {} self.labels = {} # 创建主控件 self.main_widget = QtWidgets.QWidget() self.main_widget.setObjectName("riggingMainWidget") # 初始化UI self.create_widgets() self.create_layouts() self.create_connections() #========================================= WIDGET ======================================= def create_widgets(self): """ 创建绑定系统UI控件 包括按钮、标签、列表等 """ # 标题标签 - 使用HTML格式化标题 title_text = f"

{LANG.get('rigging_title', '骨骼绑定')}

" self.controls["title_label"] = QtWidgets.QLabel(title_text) self.controls["title_label"].setObjectName("riggingTitleLabel") self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter) self.controls["title_label"].setMaximumHeight(30) # 限制标题高度 # 创建主分割器 self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical) self.splitters["main_splitter"].setObjectName("riggingMainSplitter") # 1. Presets 面板 self.controls["presets_panel"] = QtWidgets.QWidget() self.controls["presets_panel"].setObjectName("presetsPanel") # Presets 组 self.controls["presets_group"] = QtWidgets.QGroupBox(LANG.get("presets", "Presets")) self.controls["presets_group"].setObjectName("presetsGroup") # 创建预设显示区域 self.controls["presets_scroll_area"] = QtWidgets.QScrollArea() self.controls["presets_scroll_area"].setWidgetResizable(True) self.controls["presets_scroll_area"].setObjectName("presetsScrollArea") # 预设内容区域 self.controls["presets_content"] = QtWidgets.QWidget() self.controls["presets_content"].setObjectName("presetsContent") # 预设流布局 self.controls["presets_flow_layout"] = QtWidgets.QGridLayout(self.controls["presets_content"]) self.controls["presets_flow_layout"].setObjectName("presetsFlowLayout") self.controls["presets_flow_layout"].setContentsMargins(5, 5, 5, 5) self.controls["presets_flow_layout"].setSpacing(10) # 添加测试预设项 for i in range(6): # 添加6个预设项,如图中所示 col = i % 6 row = i // 6 preset_widget = QtWidgets.QWidget() preset_widget.setObjectName(f"preset_{i}") preset_widget.setMinimumSize(120, 150) # 设置预设项大小 preset_widget.setMaximumSize(120, 150) # 预设布局 preset_layout = QtWidgets.QVBoxLayout(preset_widget) preset_layout.setContentsMargins(0, 0, 0, 0) preset_layout.setSpacing(2) # 预设图片 preset_image = QtWidgets.QLabel() preset_image.setObjectName(f"preset_image_{i}") preset_image.setMinimumSize(120, 120) preset_image.setMaximumSize(120, 120) preset_image.setScaledContents(True) preset_image.setStyleSheet("background-color: #333333; border: 1px solid #555555;") # 加载测试图片 pixmap = QtGui.QPixmap(os.path.join(ASSETS_PATH, "metahuman_placeholder.png")) if not pixmap.isNull(): preset_image.setPixmap(pixmap) # 预设标签 preset_label = QtWidgets.QLabel("METAHUMAN") preset_label.setObjectName(f"preset_label_{i}") preset_label.setAlignment(QtCore.Qt.AlignCenter) preset_label.setStyleSheet("color: white; background-color: rgba(0, 0, 0, 128);") # 添加到布局 preset_layout.addWidget(preset_image) preset_layout.addWidget(preset_label) # 添加到流布局 self.controls["presets_flow_layout"].addWidget(preset_widget, row, col) # 设置滚动区域内容 self.controls["presets_scroll_area"].setWidget(self.controls["presets_content"]) # 预设底部滑块和按钮 self.controls["presets_slider_layout"] = QtWidgets.QHBoxLayout() self.controls["presets_slider_layout"].setContentsMargins(5, 5, 5, 5) self.controls["presets_slider_layout"].setSpacing(5) # 数量显示 self.controls["presets_count_label"] = QtWidgets.QLabel("99") self.controls["presets_count_label"].setObjectName("presetsCountLabel") self.controls["presets_count_label"].setAlignment(QtCore.Qt.AlignCenter) self.controls["presets_count_label"].setStyleSheet("font-weight: bold;") # 滑块 self.controls["presets_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.controls["presets_slider"].setObjectName("presetsSlider") self.controls["presets_slider"].setMinimum(0) self.controls["presets_slider"].setMaximum(100) self.controls["presets_slider"].setValue(50) # 导出预设按钮 self.buttons["export_presets"] = QtWidgets.QPushButton(LANG.get("export_presets", "导出预设")) self.buttons["export_presets"].setObjectName("exportPresetsButton") self.buttons["export_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "export.png"))) # 导入预设按钮 self.buttons["import_presets"] = QtWidgets.QPushButton(LANG.get("import_presets", "导入预设")) self.buttons["import_presets"].setObjectName("importPresetsButton") self.buttons["import_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import.png"))) # 添加到滑块布局 self.controls["presets_slider_layout"].addWidget(self.controls["presets_count_label"]) self.controls["presets_slider_layout"].addWidget(self.controls["presets_slider"]) self.controls["presets_slider_layout"].addWidget(self.buttons["export_presets"]) self.controls["presets_slider_layout"].addWidget(self.buttons["import_presets"]) # 2. Assets 面板 self.controls["assets_panel"] = QtWidgets.QWidget() self.controls["assets_panel"].setObjectName("assetsPanel") # Assets 组 self.controls["assets_group"] = QtWidgets.QGroupBox(LANG.get("assets", "Assets")) self.controls["assets_group"].setObjectName("assetsGroup") # 项目路径标签和输入框 self.controls["project_path_label"] = QtWidgets.QLabel(LANG.get("project_path", "项目路径:")) self.controls["project_path_label"].setObjectName("projectPathLabel") self.controls["project_path_input"] = QtWidgets.QLineEdit() self.controls["project_path_input"].setObjectName("projectPathInput") self.controls["project_path_input"].setText("D:/Personal/Document/maya/SuperRiggingEditor/files/data/MetaHuman") # 浏览按钮 self.buttons["browse_path"] = QtWidgets.QPushButton("...") self.buttons["browse_path"].setObjectName("browsePathButton") self.buttons["browse_path"].setFixedWidth(30) # Presets DNA 标签和输入框 self.controls["presets_dna_label"] = QtWidgets.QLabel(LANG.get("presets_dna", "Presets DNA:")) self.controls["presets_dna_label"].setObjectName("presetsDnaLabel") self.controls["presets_dna_input"] = QtWidgets.QLineEdit() self.controls["presets_dna_input"].setObjectName("presetsDnaInput") # 浏览按钮 self.buttons["browse_dna"] = QtWidgets.QPushButton("...") self.buttons["browse_dna"].setObjectName("browseDnaButton") self.buttons["browse_dna"].setFixedWidth(30) # 3. Descriptor 面板 self.controls["descriptor_panel"] = QtWidgets.QWidget() self.controls["descriptor_panel"].setObjectName("descriptorPanel") # Descriptor 组 self.controls["descriptor_group"] = QtWidgets.QGroupBox(LANG.get("descriptor", "Descriptor")) self.controls["descriptor_group"].setObjectName("descriptorGroup") # 名称标签和输入框 self.controls["name_label"] = QtWidgets.QLabel(LANG.get("name", "名称:")) self.controls["name_label"].setObjectName("nameLabel") self.controls["name_input"] = QtWidgets.QLineEdit() self.controls["name_input"].setObjectName("nameInput") # 原型标签和下拉框 self.controls["archetype_label"] = QtWidgets.QLabel(LANG.get("archetype", "原型:")) self.controls["archetype_label"].setObjectName("archetypeLabel") self.controls["archetype_combo"] = QtWidgets.QComboBox() self.controls["archetype_combo"].setObjectName("archetypeCombo") self.controls["archetype_combo"].addItem("asian") self.controls["archetype_combo"].addItem("caucasian") self.controls["archetype_combo"].addItem("african") # 性别标签和下拉框 self.controls["gender_label"] = QtWidgets.QLabel(LANG.get("gender", "性别:")) self.controls["gender_label"].setObjectName("genderLabel") self.controls["gender_combo"] = QtWidgets.QComboBox() self.controls["gender_combo"].setObjectName("genderCombo") self.controls["gender_combo"].addItem("female") self.controls["gender_combo"].addItem("male") # 年龄标签和输入框 self.controls["age_label"] = QtWidgets.QLabel(LANG.get("age", "年龄:")) self.controls["age_label"].setObjectName("ageLabel") self.controls["age_spinner"] = QtWidgets.QSpinBox() self.controls["age_spinner"].setObjectName("ageSpinner") self.controls["age_spinner"].setMinimum(1) self.controls["age_spinner"].setMaximum(100) self.controls["age_spinner"].setValue(18) # 平移单位标签和下拉框 self.controls["translation_unit_label"] = QtWidgets.QLabel(LANG.get("translation_unit", "平移单位:")) self.controls["translation_unit_label"].setObjectName("translationUnitLabel") self.controls["translation_unit_combo"] = QtWidgets.QComboBox() self.controls["translation_unit_combo"].setObjectName("translationUnitCombo") self.controls["translation_unit_combo"].addItem("cm") self.controls["translation_unit_combo"].addItem("mm") self.controls["translation_unit_combo"].addItem("m") # 旋转单位标签和下拉框 self.controls["rotation_unit_label"] = QtWidgets.QLabel(LANG.get("rotation_unit", "旋转单位:")) self.controls["rotation_unit_label"].setObjectName("rotationUnitLabel") self.controls["rotation_unit_combo"] = QtWidgets.QComboBox() self.controls["rotation_unit_combo"].setObjectName("rotationUnitCombo") self.controls["rotation_unit_combo"].addItem("degrees") self.controls["rotation_unit_combo"].addItem("radians") # 坐标系统标签和下拉框 self.controls["coordinate_system_label"] = QtWidgets.QLabel(LANG.get("coordinate_system", "坐标系统:")) self.controls["coordinate_system_label"].setObjectName("coordinateSystemLabel") self.controls["coordinate_system_combo"] = QtWidgets.QComboBox() self.controls["coordinate_system_combo"].setObjectName("coordinateSystemCombo") self.controls["coordinate_system_combo"].addItem("YAxisUp") self.controls["coordinate_system_combo"].addItem("ZAxisUp") # LOD数量标签和输入框 self.controls["lod_count_label"] = QtWidgets.QLabel(LANG.get("lod_count", "LOD数量:")) self.controls["lod_count_label"].setObjectName("lodCountLabel") self.controls["lod_count_spinner"] = QtWidgets.QSpinBox() self.controls["lod_count_spinner"].setObjectName("lodCountSpinner") self.controls["lod_count_spinner"].setMinimum(0) self.controls["lod_count_spinner"].setMaximum(8) self.controls["lod_count_spinner"].setValue(0) # 底部按钮区域 self.controls["bottom_buttons_panel"] = QtWidgets.QWidget() self.controls["bottom_buttons_panel"].setObjectName("bottomButtonsPanel") # 删除所有按钮 self.buttons["remove_all"] = QtWidgets.QPushButton(LANG.get("remove_all", "删除所有")) self.buttons["remove_all"].setObjectName("removeAllButton") self.buttons["remove_all"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "delete.png"))) # 导入骨骼按钮 self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼")) self.buttons["import_skeleton"].setObjectName("importSkeletonButton") self.buttons["import_skeleton"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import_skeleton.png"))) # 生成绑定按钮 self.buttons["build_rigging"] = QtWidgets.QPushButton(LANG.get("build_rigging", "生成绑定")) self.buttons["build_rigging"].setObjectName("buildRiggingButton") self.buttons["build_rigging"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "build_rigging.png"))) # 左侧面板控件 - 控制器列表 self.controls["controller_group"] = QtWidgets.QGroupBox("Controllers [000]") self.controls["controller_group"].setObjectName("controllerGroup") # 控制器列表 self.controls["controller_list"] = QtWidgets.QListWidget() self.controls["controller_list"].setObjectName("controllerList") # 添加测试项目 for i in range(3): item = QtWidgets.QListWidgetItem(f"Controller_{i}") self.controls["controller_list"].addItem(item) # 控制器操作按钮 self.buttons["add_controller"] = QtWidgets.QPushButton(LANG.get("add_controller", "添加控制器")) self.buttons["add_controller"].setObjectName("addControllerButton") self.buttons["remove_controller"] = QtWidgets.QPushButton(LANG.get("remove_controller", "移除控制器")) self.buttons["remove_controller"].setObjectName("removeControllerButton") self.buttons["duplicate_controller"] = QtWidgets.QPushButton(LANG.get("duplicate_controller", "复制控制器")) self.buttons["duplicate_controller"].setObjectName("duplicateControllerButton") # 右侧面板控件 - 关节属性 self.controls["joint_properties_group"] = QtWidgets.QGroupBox(LANG.get("joint_properties", "关节属性")) self.controls["joint_properties_group"].setObjectName("jointPropertiesGroup") # 关节名称标签和输入框 self.controls["joint_name_label"] = QtWidgets.QLabel(LANG.get("name", "名称:")) self.controls["joint_name_label"].setObjectName("jointNameLabel") self.controls["joint_name_input"] = QtWidgets.QLineEdit() self.controls["joint_name_input"].setObjectName("jointNameInput") self.controls["joint_name_input"].setPlaceholderText(LANG.get("enter_joint_name", "输入关节名称")) # 关节位置标签和输入框 self.controls["joint_position_label"] = QtWidgets.QLabel(LANG.get("position", "位置:")) self.controls["joint_position_label"].setObjectName("jointPositionLabel") # X坐标 self.controls["joint_x_label"] = QtWidgets.QLabel("X:") self.controls["joint_x_label"].setObjectName("jointXLabel") self.controls["joint_x_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_x_input"].setObjectName("jointXInput") # Y坐标 self.controls["joint_y_label"] = QtWidgets.QLabel("Y:") self.controls["joint_y_label"].setObjectName("jointYLabel") self.controls["joint_y_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_y_input"].setObjectName("jointYInput") # Z坐标 self.controls["joint_z_label"] = QtWidgets.QLabel("Z:") self.controls["joint_z_label"].setObjectName("jointZLabel") self.controls["joint_z_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_z_input"].setObjectName("jointZInput") # 关节旋转标签和输入框 self.controls["joint_rotation_label"] = QtWidgets.QLabel(LANG.get("rotation", "旋转:")) self.controls["joint_rotation_label"].setObjectName("jointRotationLabel") # X旋转 self.controls["joint_rx_label"] = QtWidgets.QLabel("X:") self.controls["joint_rx_label"].setObjectName("jointRXLabel") self.controls["joint_rx_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_rx_input"].setObjectName("jointRXInput") # Y旋转 self.controls["joint_ry_label"] = QtWidgets.QLabel("Y:") self.controls["joint_ry_label"].setObjectName("jointRYLabel") self.controls["joint_ry_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_ry_input"].setObjectName("jointRYInput") # Z旋转 self.controls["joint_rz_label"] = QtWidgets.QLabel("Z:") self.controls["joint_rz_label"].setObjectName("jointRZLabel") self.controls["joint_rz_input"] = QtWidgets.QLineEdit("0.0") self.controls["joint_rz_input"].setObjectName("jointRZInput") # 关节缩放标签和输入框 self.controls["joint_scale_label"] = QtWidgets.QLabel(LANG.get("scale", "缩放:")) self.controls["joint_scale_label"].setObjectName("jointScaleLabel") # X缩放 self.controls["joint_sx_label"] = QtWidgets.QLabel("X:") self.controls["joint_sx_label"].setObjectName("jointSXLabel") self.controls["joint_sx_input"] = QtWidgets.QLineEdit("1.0") self.controls["joint_sx_input"].setObjectName("jointSXInput") # Y缩放 self.controls["joint_sy_label"] = QtWidgets.QLabel("Y:") self.controls["joint_sy_label"].setObjectName("jointSYLabel") self.controls["joint_sy_input"] = QtWidgets.QLineEdit("1.0") self.controls["joint_sy_input"].setObjectName("jointSYInput") # Z缩放 self.controls["joint_sz_label"] = QtWidgets.QLabel("Z:") self.controls["joint_sz_label"].setObjectName("jointSZLabel") self.controls["joint_sz_input"] = QtWidgets.QLineEdit("1.0") self.controls["joint_sz_input"].setObjectName("jointSZInput") # 关节属性按钮 self.buttons["apply_joint_properties"] = QtWidgets.QPushButton(LANG.get("apply", "应用")) self.buttons["apply_joint_properties"].setObjectName("applyJointPropertiesButton") self.buttons["reset_joint_properties"] = QtWidgets.QPushButton(LANG.get("reset", "重置")) self.buttons["reset_joint_properties"].setObjectName("resetJointPropertiesButton") # 右侧面板控件 - 绑定工具 self.controls["binding_tools_group"] = QtWidgets.QGroupBox(LANG.get("binding_tools", "绑定工具")) self.controls["binding_tools_group"].setObjectName("bindingToolsGroup") # 绑定工具按钮 self.buttons["create_binding"] = QtWidgets.QPushButton(LANG.get("create_binding", "创建绑定")) self.buttons["create_binding"].setObjectName("createBindingButton") self.buttons["copy_skin"] = QtWidgets.QPushButton(LANG.get("copy_skin", "复制蒙皮")) self.buttons["copy_skin"].setObjectName("copySkinButton") self.buttons["mirror_skin"] = QtWidgets.QPushButton(LANG.get("mirror_skin", "镜像蒙皮")) self.buttons["mirror_skin"].setObjectName("mirrorSkinButton") self.buttons["paint_weights"] = QtWidgets.QPushButton(LANG.get("paint_weights", "绘制权重")) self.buttons["paint_weights"].setObjectName("paintWeightsButton") # 底部工具面板 # DNA部分 self.controls["dna_group"] = QtWidgets.QGroupBox(LANG.get("dna", "DNA")) self.controls["dna_group"].setObjectName("dnaGroup") self.buttons["import_dna"] = QtWidgets.QPushButton(LANG.get("import_dna", "导入DNA")) self.buttons["import_dna"].setObjectName("importDnaButton") self.buttons["export_dna"] = QtWidgets.QPushButton(LANG.get("export_dna", "导出DNA")) self.buttons["export_dna"].setObjectName("exportDnaButton") self.buttons["calibrate_dna"] = QtWidgets.QPushButton(LANG.get("calibrate_dna", "校准DNA")) self.buttons["calibrate_dna"].setObjectName("calibrateDnaButton") # 骨骼部分 self.controls["skeleton_tools_group"] = QtWidgets.QGroupBox(LANG.get("skeleton_tools", "骨骼工具")) self.controls["skeleton_tools_group"].setObjectName("skeletonToolsGroup") self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼")) self.buttons["import_skeleton"].setObjectName("importSkeletonButton") self.buttons["export_skeleton"] = QtWidgets.QPushButton(LANG.get("export_skeleton", "导出骨骼")) self.buttons["export_skeleton"].setObjectName("exportSkeletonButton") self.buttons["calibrate_skeleton"] = QtWidgets.QPushButton(LANG.get("calibrate_skeleton", "校准骨骼")) self.buttons["calibrate_skeleton"].setObjectName("calibrateSkeletonButton") # 工具部分 self.controls["rigging_tools_group"] = QtWidgets.QGroupBox(LANG.get("rigging_tools", "绑定工具")) self.controls["rigging_tools_group"].setObjectName("riggingToolsGroup") self.buttons["generate_controllers"] = QtWidgets.QPushButton(LANG.get("generate_controllers", "生成控制器")) self.buttons["generate_controllers"].setObjectName("generateControllersButton") self.buttons["generate_body"] = QtWidgets.QPushButton(LANG.get("generate_body", "生成身体")) self.buttons["generate_body"].setObjectName("generateBodyButton") self.buttons["clean_rigging"] = QtWidgets.QPushButton(LANG.get("clean_rigging", "清理绑定")) self.buttons["clean_rigging"].setObjectName("cleanRiggingButton") #========================================= LAYOUT ======================================= def create_layouts(self): """ 创建绑定系统UI布局 组织控件的排列和层次结构 """ # 创建主布局 main_layout = QtWidgets.QVBoxLayout(self.main_widget) main_layout.setContentsMargins(5, 5, 5, 5) main_layout.setSpacing(5) # 添加标题 main_layout.addWidget(self.controls["title_label"]) # 添加主分割器到主布局 main_layout.addWidget(self.splitters["main_splitter"]) # 1. Presets 面板布局 presets_layout = QtWidgets.QVBoxLayout(self.controls["presets_panel"]) presets_layout.setContentsMargins(0, 0, 0, 0) presets_layout.setSpacing(5) # Presets 组布局 presets_group_layout = QtWidgets.QVBoxLayout(self.controls["presets_group"]) presets_group_layout.setContentsMargins(5, 5, 5, 5) presets_group_layout.setSpacing(5) # 添加预设滚动区域 presets_group_layout.addWidget(self.controls["presets_scroll_area"]) # 添加预设底部滑块布局 presets_group_layout.addLayout(self.controls["presets_slider_layout"]) # 添加Presets组到Presets面板 presets_layout.addWidget(self.controls["presets_group"]) # 2. Assets 面板布局 assets_layout = QtWidgets.QVBoxLayout(self.controls["assets_panel"]) assets_layout.setContentsMargins(0, 0, 0, 0) assets_layout.setSpacing(5) # Assets 组布局 assets_group_layout = QtWidgets.QGridLayout(self.controls["assets_group"]) assets_group_layout.setContentsMargins(5, 5, 5, 5) assets_group_layout.setSpacing(5) # 添加项目路径标签和输入框 assets_group_layout.addWidget(self.controls["project_path_label"], 0, 0) assets_group_layout.addWidget(self.controls["project_path_input"], 0, 1) assets_group_layout.addWidget(self.buttons["browse_path"], 0, 2) # 添加Presets DNA标签和输入框 assets_group_layout.addWidget(self.controls["presets_dna_label"], 1, 0) assets_group_layout.addWidget(self.controls["presets_dna_input"], 1, 1) assets_group_layout.addWidget(self.buttons["browse_dna"], 1, 2) # 添加Assets组到Assets面板 assets_layout.addWidget(self.controls["assets_group"]) # 3. Descriptor 面板布局 descriptor_layout = QtWidgets.QVBoxLayout(self.controls["descriptor_panel"]) descriptor_layout.setContentsMargins(0, 0, 0, 0) descriptor_layout.setSpacing(5) # Descriptor 组布局 descriptor_group_layout = QtWidgets.QGridLayout(self.controls["descriptor_group"]) descriptor_group_layout.setContentsMargins(5, 5, 5, 5) descriptor_group_layout.setSpacing(5) # 添加名称标签和输入框 descriptor_group_layout.addWidget(self.controls["name_label"], 0, 0) descriptor_group_layout.addWidget(self.controls["name_input"], 0, 1, 1, 3) # 添加原型标签和下拉框 descriptor_group_layout.addWidget(self.controls["archetype_label"], 1, 0) descriptor_group_layout.addWidget(self.controls["archetype_combo"], 1, 1) # 添加性别标签和下拉框 descriptor_group_layout.addWidget(self.controls["gender_label"], 1, 2) descriptor_group_layout.addWidget(self.controls["gender_combo"], 1, 3) # 添加年龄标签和输入框 descriptor_group_layout.addWidget(self.controls["age_label"], 2, 0) descriptor_group_layout.addWidget(self.controls["age_spinner"], 2, 1) # 添加平移单位标签和下拉框 descriptor_group_layout.addWidget(self.controls["translation_unit_label"], 3, 0) descriptor_group_layout.addWidget(self.controls["translation_unit_combo"], 3, 1) # 添加旋转单位标签和下拉框 descriptor_group_layout.addWidget(self.controls["rotation_unit_label"], 3, 2) descriptor_group_layout.addWidget(self.controls["rotation_unit_combo"], 3, 3) # 添加坐标系统标签和下拉框 descriptor_group_layout.addWidget(self.controls["coordinate_system_label"], 4, 0) descriptor_group_layout.addWidget(self.controls["coordinate_system_combo"], 4, 1) # 添加LOD数量标签和输入框 descriptor_group_layout.addWidget(self.controls["lod_count_label"], 4, 2) descriptor_group_layout.addWidget(self.controls["lod_count_spinner"], 4, 3) # 添加Descriptor组到Descriptor面板 descriptor_layout.addWidget(self.controls["descriptor_group"]) # 添加各个面板到主分割器 self.splitters["main_splitter"].addWidget(self.controls["presets_panel"]) self.splitters["main_splitter"].addWidget(self.controls["assets_panel"]) self.splitters["main_splitter"].addWidget(self.controls["descriptor_panel"]) # 底部按钮区域布局 bottom_buttons_layout = QtWidgets.QHBoxLayout(self.controls["bottom_buttons_panel"]) bottom_buttons_layout.setContentsMargins(5, 5, 5, 5) bottom_buttons_layout.setSpacing(10) # 添加底部按钮 bottom_buttons_layout.addWidget(self.buttons["remove_all"]) bottom_buttons_layout.addStretch(1) # 添加弹性空间 bottom_buttons_layout.addWidget(self.buttons["import_skeleton"]) bottom_buttons_layout.addWidget(self.buttons["build_rigging"]) # 添加底部按钮区域到主布局 main_layout.addWidget(self.controls["bottom_buttons_panel"]) # 设置分割器初始大小 self.splitters["main_splitter"].setSizes([400, 100, 200]) # 设置分割器的伸缩因子 for i in range(self.splitters["main_splitter"].count()): self.splitters["main_splitter"].setStretchFactor(i, 1) #======================================= FUNCTIONS ====================================== def create_connections(self): """ 创建信号连接 """ # 创建信号映射字典 signal_mapping = { 'buttons': { # 绑定所有功能按钮 'add_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.add_joint}, 'remove_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_joint}, 'duplicate_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_joint}, 'add_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.add_controller}, 'remove_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_controller}, 'duplicate_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_controller}, 'import_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.import_dna}, 'export_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.export_dna}, 'calibrate_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.calibrate_dna}, # 已创建的按钮 'browse_path': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "项目路径", self.controls["project_path_input"])}, 'browse_dna': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "DNA文件", self.controls["presets_dna_input"], "dna")}, 'export_presets': {'signal': 'clicked', 'handler': utils_rigging.export_presets}, 'import_presets': {'signal': 'clicked', 'handler': utils_rigging.import_presets}, }, 'splitters': { 'main_splitter': {'signal': 'splitterMoved', 'handler': lambda pos, index: ui_utils.on_splitter_moved(self, pos, index)}, } } # 使用ui_utils中的通用函数连接信号 ui_utils.connect_ui_signals(self, signal_mapping) # 连接Maya选择变化事件 ui_utils.connect_maya_selection_changed(self, lambda: utils_rigging.on_selection_changed(self), self.main_widget)