426 lines
21 KiB
Python
426 lines
21 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Definition UI Module for Plugin
|
||
定义系统UI模块 - 负责显示DNA定义编辑界面和基础操作
|
||
基本功能:
|
||
- LOD, Meshes, Joints, Blendshape, AnimatedMap 加载和刷新
|
||
- 写入: 写入关节默认位置,写入几何体,写入蒙皮,写入混合变形目标
|
||
- 创建:创建混合变形,绑定蒙皮,取消蒙皮
|
||
- 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设
|
||
"""
|
||
#========================================= 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_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
|
||
TOOL_WIDTH = config.TOOL_WIDTH
|
||
TOOL_HEIGHT = config.TOOL_HEIGHT
|
||
#========================================= LOCATION =======================================
|
||
from scripts.ui import localization
|
||
LANG = localization.LANG
|
||
|
||
class DefinitionUI(ui_utils.BaseUI):
|
||
"""
|
||
定义系统UI类 - 负责显示DNA定义编辑界面和基础操作
|
||
继承自BaseUI类,实现DNA定义相关的UI功能
|
||
"""
|
||
#========================================== INIT ========================================
|
||
def __init__(self):
|
||
"""
|
||
初始化定义系统UI
|
||
创建主控件和布局,并连接信号和槽
|
||
"""
|
||
super(DefinitionUI, self).__init__()
|
||
|
||
# 设置单例实例
|
||
DefinitionUI._instance = self
|
||
|
||
# 创建主控件
|
||
self.main_widget = QtWidgets.QWidget()
|
||
self.main_widget.setObjectName("definitionMainWidget")
|
||
|
||
# 初始化字典
|
||
self.controls = {}
|
||
self.layouts = {}
|
||
self.splitters = {}
|
||
self.buttons = {}
|
||
|
||
# 初始化UI
|
||
self.create_widgets()
|
||
self.create_layouts()
|
||
self.create_connections()
|
||
|
||
# 添加左右面板到分割器
|
||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||
|
||
# 设置分割器所有子元素的最小尺寸为0,确保可以自由调整
|
||
ui_utils.set_splitter_children_minimum_size(self, recursive=True)
|
||
|
||
# 设置所有控件的最小尺寸为0,确保分割器可以自由移动
|
||
ui_utils.set_all_controls_minimum_size(self)
|
||
|
||
# 使用ui_utils中的函数强制设置均等大小
|
||
ui_utils.force_equal_splitter_sizes(self)
|
||
|
||
#========================================= WIDGET =======================================
|
||
def create_widgets(self):
|
||
"""
|
||
创建定义系统UI控件
|
||
包括按钮、标签、列表等
|
||
"""
|
||
# 标题标签 - 使用HTML格式化标题
|
||
title_text = f"<h4 style='margin:0;padding:5px;'>{LANG.get('definition_title', 'DNA定义')}</h4>"
|
||
self.controls["title_label"] = QtWidgets.QLabel(title_text)
|
||
self.controls["title_label"].setObjectName("definitionTitleLabel")
|
||
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
|
||
|
||
# 主分割器
|
||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||
self.splitters["main_splitter"].setObjectName("definitionMainSplitter")
|
||
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
|
||
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
|
||
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果
|
||
|
||
# 左侧面板
|
||
self.controls["left_panel"] = QtWidgets.QWidget()
|
||
self.controls["left_panel"].setObjectName("definitionLeftPanel")
|
||
|
||
# 右侧面板
|
||
self.controls["right_panel"] = QtWidgets.QWidget()
|
||
self.controls["right_panel"].setObjectName("definitionRightPanel")
|
||
|
||
# 左侧面板控件
|
||
# LODs组
|
||
self.controls["lods_group"] = QtWidgets.QGroupBox("LODs")
|
||
self.controls["lods_group"].setObjectName("lodsGroup")
|
||
|
||
# LODs列表
|
||
self.controls["lods_list"] = QtWidgets.QListWidget()
|
||
self.controls["lods_list"].setObjectName("lodsList")
|
||
|
||
# 定义LOD关联按钮
|
||
self.buttons["define_lod_relations"] = QtWidgets.QPushButton(LANG.get("define_lod_relations", "定义LOD关联"))
|
||
self.buttons["define_lod_relations"].setObjectName("defineLodRelationsButton")
|
||
|
||
# Meshes组
|
||
self.controls["meshes_group"] = QtWidgets.QGroupBox("Meshes [000]")
|
||
self.controls["meshes_group"].setObjectName("meshesGroup")
|
||
|
||
# Meshes列表
|
||
self.controls["meshes_list"] = QtWidgets.QListWidget()
|
||
self.controls["meshes_list"].setObjectName("meshesList")
|
||
|
||
# 创建几何体按钮
|
||
self.buttons["create_geometry"] = QtWidgets.QPushButton(LANG.get("create_geometry", "创建几何体"))
|
||
self.buttons["create_geometry"].setObjectName("createGeometryButton")
|
||
|
||
# 右侧面板控件
|
||
# Joints组
|
||
self.controls["joints_group"] = QtWidgets.QGroupBox("Joints [000]")
|
||
self.controls["joints_group"].setObjectName("jointsGroup")
|
||
|
||
# Joints列表
|
||
self.controls["joints_list"] = QtWidgets.QListWidget()
|
||
self.controls["joints_list"].setObjectName("jointsList")
|
||
|
||
# BlendShapes组
|
||
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("BlendShapes [000]")
|
||
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
|
||
|
||
# BlendShapes列表
|
||
self.controls["blendshapes_list"] = QtWidgets.QListWidget()
|
||
self.controls["blendshapes_list"].setObjectName("blendshapesList")
|
||
|
||
# AnimatedMap组
|
||
self.controls["animatedmap_group"] = QtWidgets.QGroupBox("AnimatedMap [000]")
|
||
self.controls["animatedmap_group"].setObjectName("animatedmapGroup")
|
||
|
||
# AnimatedMap列表
|
||
self.controls["animatedmap_list"] = QtWidgets.QListWidget()
|
||
self.controls["animatedmap_list"].setObjectName("animatedmapList")
|
||
|
||
# 底部工具面板
|
||
# 导入部分
|
||
self.controls["import_label"] = QtWidgets.QLabel(LANG.get("import", "导入"))
|
||
self.controls["import_label"].setObjectName("importLabel")
|
||
self.controls["import_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
|
||
self.buttons["import_joint_system"] = QtWidgets.QPushButton(LANG.get("import_joint_system", "导入关节系统"))
|
||
self.buttons["import_joint_system"].setObjectName("importJointSystemButton")
|
||
|
||
self.buttons["import_geometry"] = QtWidgets.QPushButton(LANG.get("import_geometry", "导入几何体"))
|
||
self.buttons["import_geometry"].setObjectName("importGeometryButton")
|
||
|
||
self.buttons["import_blendshape_target"] = QtWidgets.QPushButton(LANG.get("import_blendshape_target", "导入形状混合目标"))
|
||
self.buttons["import_blendshape_target"].setObjectName("importBlendshapeTargetButton")
|
||
|
||
self.buttons["import_animated_map"] = QtWidgets.QPushButton(LANG.get("import_animated_map", "导入动画贴图"))
|
||
self.buttons["import_animated_map"].setObjectName("importAnimatedMapButton")
|
||
|
||
# 创建部分
|
||
self.controls["create_label"] = QtWidgets.QLabel(LANG.get("create", "创建"))
|
||
self.controls["create_label"].setObjectName("createLabel")
|
||
self.controls["create_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
|
||
self.buttons["create_neutral_pose"] = QtWidgets.QPushButton(LANG.get("create_neutral_pose", "创建中性姿势"))
|
||
self.buttons["create_neutral_pose"].setObjectName("createNeutralPoseButton")
|
||
|
||
self.buttons["bind_geometry"] = QtWidgets.QPushButton(LANG.get("bind_geometry", "绑定几何体"))
|
||
self.buttons["bind_geometry"].setObjectName("bindGeometryButton")
|
||
|
||
self.buttons["take_pose"] = QtWidgets.QPushButton(LANG.get("take_pose", "取消姿势"))
|
||
self.buttons["take_pose"].setObjectName("takePoseButton")
|
||
|
||
# 工具部分
|
||
self.controls["tools_label"] = QtWidgets.QLabel(LANG.get("tools", "工具"))
|
||
self.controls["tools_label"].setObjectName("toolsLabel")
|
||
self.controls["tools_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
|
||
self.buttons["reposition_all_joints"] = QtWidgets.QPushButton(LANG.get("reposition_all_joints", "重新定位所有关节"))
|
||
self.buttons["reposition_all_joints"].setObjectName("repositionAllJointsButton")
|
||
|
||
self.buttons["reposition_selected_joints"] = QtWidgets.QPushButton(LANG.get("reposition_selected_joints", "重新定位选定关节"))
|
||
self.buttons["reposition_selected_joints"].setObjectName("repositionSelectedJointsButton")
|
||
|
||
self.buttons["reposition_all_head_joints"] = QtWidgets.QPushButton(LANG.get("reposition_all_head_joints", "重新定位所有头部关节"))
|
||
self.buttons["reposition_all_head_joints"].setObjectName("repositionAllHeadJointsButton")
|
||
|
||
self.buttons["quick_preset"] = QtWidgets.QPushButton(LANG.get("quick_preset", "快速预设"))
|
||
self.buttons["quick_preset"].setObjectName("quickPresetButton")
|
||
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", "快速创建预设"))
|
||
|
||
#========================================= 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_splitter_layout"] = QtWidgets.QHBoxLayout()
|
||
self.layouts["main_splitter_layout"].setContentsMargins(0, 0, 0, 0)
|
||
self.layouts["main_splitter_layout"].setSpacing(0)
|
||
self.layouts["main_splitter_layout"].addWidget(self.splitters["main_splitter"])
|
||
|
||
# 添加主分割器布局到主布局
|
||
self.layouts["main_layout"].addLayout(self.layouts["main_splitter_layout"])
|
||
|
||
# 左侧面板布局
|
||
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
|
||
self.layouts["left_layout"].setContentsMargins(0, 0, 0, 0)
|
||
self.layouts["left_layout"].setSpacing(5)
|
||
|
||
# 左侧分割器
|
||
self.splitters["left_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
|
||
self.splitters["left_splitter"].setObjectName("definitionLeftSplitter")
|
||
self.layouts["left_layout"].addWidget(self.splitters["left_splitter"])
|
||
|
||
# LODs组布局
|
||
self.layouts["lods_layout"] = QtWidgets.QVBoxLayout(self.controls["lods_group"])
|
||
self.layouts["lods_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.layouts["lods_layout"].setSpacing(5)
|
||
|
||
# 添加LODs列表
|
||
self.layouts["lods_layout"].addWidget(self.controls["lods_list"])
|
||
|
||
# 定义LOD关联按钮
|
||
self.layouts["lods_layout"].addWidget(self.buttons["define_lod_relations"])
|
||
|
||
# Meshes组布局
|
||
self.layouts["meshes_layout"] = QtWidgets.QVBoxLayout(self.controls["meshes_group"])
|
||
self.layouts["meshes_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.layouts["meshes_layout"].setSpacing(5)
|
||
|
||
# 添加Meshes列表
|
||
self.layouts["meshes_layout"].addWidget(self.controls["meshes_list"])
|
||
|
||
# 创建几何体按钮
|
||
self.layouts["meshes_layout"].addWidget(self.buttons["create_geometry"])
|
||
|
||
# 添加到左侧分割器
|
||
self.splitters["left_splitter"].addWidget(self.controls["lods_group"])
|
||
self.splitters["left_splitter"].addWidget(self.controls["meshes_group"])
|
||
|
||
# 右侧面板布局
|
||
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
|
||
self.layouts["right_layout"].setContentsMargins(0, 0, 0, 0)
|
||
self.layouts["right_layout"].setSpacing(5)
|
||
|
||
# 右侧分割器
|
||
self.splitters["right_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
|
||
self.splitters["right_splitter"].setObjectName("definitionRightSplitter")
|
||
self.layouts["right_layout"].addWidget(self.splitters["right_splitter"])
|
||
|
||
# Joints组布局
|
||
self.layouts["joints_layout"] = QtWidgets.QVBoxLayout(self.controls["joints_group"])
|
||
self.layouts["joints_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.layouts["joints_layout"].setSpacing(5)
|
||
|
||
# 添加Joints列表
|
||
self.layouts["joints_layout"].addWidget(self.controls["joints_list"])
|
||
|
||
# BlendShapes组布局
|
||
self.layouts["blendshapes_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshapes_group"])
|
||
self.layouts["blendshapes_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.layouts["blendshapes_layout"].setSpacing(5)
|
||
|
||
# 添加BlendShapes列表
|
||
self.layouts["blendshapes_layout"].addWidget(self.controls["blendshapes_list"])
|
||
|
||
# AnimatedMap组布局
|
||
self.layouts["animatedmap_layout"] = QtWidgets.QVBoxLayout(self.controls["animatedmap_group"])
|
||
self.layouts["animatedmap_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.layouts["animatedmap_layout"].setSpacing(5)
|
||
|
||
# 添加AnimatedMap列表
|
||
self.layouts["animatedmap_layout"].addWidget(self.controls["animatedmap_list"])
|
||
|
||
# 添加到右侧分割器
|
||
self.splitters["right_splitter"].addWidget(self.controls["joints_group"])
|
||
self.splitters["right_splitter"].addWidget(self.controls["blendshapes_group"])
|
||
self.splitters["right_splitter"].addWidget(self.controls["animatedmap_group"])
|
||
|
||
# 底部工具面板
|
||
self.layouts["bottom_panel"] = QtWidgets.QHBoxLayout()
|
||
self.layouts["bottom_panel"].setContentsMargins(0, 10, 0, 0)
|
||
self.layouts["bottom_panel"].setSpacing(10)
|
||
|
||
# 导入部分布局
|
||
self.layouts["import_layout"] = QtWidgets.QVBoxLayout()
|
||
self.layouts["import_layout"].setSpacing(5)
|
||
self.layouts["import_layout"].addWidget(self.controls["import_label"])
|
||
self.layouts["import_layout"].addWidget(self.buttons["import_joint_system"])
|
||
self.layouts["import_layout"].addWidget(self.buttons["import_geometry"])
|
||
self.layouts["import_layout"].addWidget(self.buttons["import_blendshape_target"])
|
||
self.layouts["import_layout"].addWidget(self.buttons["import_animated_map"])
|
||
|
||
# 创建部分布局
|
||
self.layouts["create_layout"] = QtWidgets.QVBoxLayout()
|
||
self.layouts["create_layout"].setSpacing(5)
|
||
self.layouts["create_layout"].addWidget(self.controls["create_label"])
|
||
self.layouts["create_layout"].addWidget(self.buttons["create_neutral_pose"])
|
||
self.layouts["create_layout"].addWidget(self.buttons["bind_geometry"])
|
||
self.layouts["create_layout"].addWidget(self.buttons["take_pose"])
|
||
self.layouts["create_layout"].addWidget(self.buttons["unbind_skin"])
|
||
|
||
# 工具部分布局
|
||
self.layouts["tools_layout"] = QtWidgets.QVBoxLayout()
|
||
self.layouts["tools_layout"].setSpacing(5)
|
||
self.layouts["tools_layout"].addWidget(self.controls["tools_label"])
|
||
self.layouts["tools_layout"].addWidget(self.buttons["reposition_all_joints"])
|
||
self.layouts["tools_layout"].addWidget(self.buttons["reposition_selected_joints"])
|
||
self.layouts["tools_layout"].addWidget(self.buttons["reposition_all_head_joints"])
|
||
self.layouts["tools_layout"].addWidget(self.buttons["quick_preset"])
|
||
|
||
# 添加三列到底部面板
|
||
self.layouts["bottom_panel"].addLayout(self.layouts["import_layout"])
|
||
self.layouts["bottom_panel"].addLayout(self.layouts["create_layout"])
|
||
self.layouts["bottom_panel"].addLayout(self.layouts["tools_layout"])
|
||
|
||
# 添加底部面板到主布局
|
||
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
|
||
|
||
#======================================= CONNECTION =====================================
|
||
def create_connections(self):
|
||
"""
|
||
连接信号和槽
|
||
设置UI控件的交互行为
|
||
"""
|
||
# 左侧面板连接
|
||
# LODs列表连接
|
||
self.controls["lods_list"].itemClicked.connect(utils_definition.lod_selected)
|
||
self.controls["lods_list"].itemSelectionChanged.connect(utils_definition.update_lod_selection)
|
||
|
||
# 定义LOD关联按钮连接
|
||
self.buttons["define_lod_relations"].clicked.connect(utils_definition.define_lod_relations)
|
||
|
||
# Meshes列表连接
|
||
self.controls["meshes_list"].itemClicked.connect(utils_definition.mesh_selected)
|
||
self.controls["meshes_list"].itemSelectionChanged.connect(utils_definition.update_mesh_selection)
|
||
|
||
# 创建几何体按钮连接
|
||
self.buttons["create_geometry"].clicked.connect(utils_definition.create_geometry)
|
||
|
||
# 右侧面板连接
|
||
# Joints列表连接
|
||
self.controls["joints_list"].itemClicked.connect(utils_definition.joint_selected)
|
||
self.controls["joints_list"].itemSelectionChanged.connect(utils_definition.update_joint_selection)
|
||
|
||
# BlendShapes列表连接
|
||
self.controls["blendshapes_list"].itemClicked.connect(utils_definition.blendshape_selected)
|
||
self.controls["blendshapes_list"].itemSelectionChanged.connect(utils_definition.update_blendshape_selection)
|
||
|
||
# AnimatedMap列表连接
|
||
self.controls["animatedmap_list"].itemClicked.connect(utils_definition.animatedmap_selected)
|
||
self.controls["animatedmap_list"].itemSelectionChanged.connect(utils_definition.update_animatedmap_selection)
|
||
|
||
# 底部工具面板连接
|
||
# 导入部分按钮连接
|
||
self.buttons["import_joint_system"].clicked.connect(utils_definition.import_joint_system)
|
||
self.buttons["import_geometry"].clicked.connect(utils_definition.import_geometry)
|
||
self.buttons["import_blendshape_target"].clicked.connect(utils_definition.import_blendshape_target)
|
||
self.buttons["import_animated_map"].clicked.connect(utils_definition.import_animated_map)
|
||
|
||
# 创建部分按钮连接
|
||
self.buttons["create_neutral_pose"].clicked.connect(utils_definition.create_neutral_pose)
|
||
self.buttons["bind_geometry"].clicked.connect(utils_definition.bind_geometry)
|
||
self.buttons["take_pose"].clicked.connect(utils_definition.take_pose)
|
||
self.buttons["unbind_skin"].clicked.connect(utils_definition.unbind_skin)
|
||
|
||
# 工具部分按钮连接
|
||
self.buttons["reposition_all_joints"].clicked.connect(utils_definition.reposition_all_joints)
|
||
self.buttons["reposition_selected_joints"].clicked.connect(utils_definition.reposition_selected_joints)
|
||
self.buttons["reposition_all_head_joints"].clicked.connect(utils_definition.reposition_all_head_joints)
|
||
self.buttons["quick_preset"].clicked.connect(utils_definition.quick_preset) |