Files
MetaFusion/scripts/ui/behaviour.py
2025-05-07 01:31:21 +08:00

678 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Behaviour UI Module for Plugin
行为系统UI模块 - 负责显示角色行为编辑界面和基础操作
基本功能:
- Blendshape自动加载刷新筛选
- 次级Blendshape自动加载刷新筛选
- Blendshape批量导出和导入
- Blendshape范围编辑
- Blendshape镜像
- Blendshape查找翻转目标
- 表情控制器还原默认表情
- 查找选择表情
- 控制面板查找
"""
#========================================= 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_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
TOOL_WIDTH = config.TOOL_WIDTH
TOOL_HEIGHT = config.TOOL_HEIGHT
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
class BehaviourUI(ui_utils.BaseUI):
"""
行为系统UI类 - 负责显示角色行为编辑界面和基础操作
继承自BaseUI类实现行为系统相关的UI功能
"""
# 类变量,存储单例实例
_instance = None
@classmethod
def get_instance(cls):
"""
获取BehaviourUI的单例实例
Returns:
BehaviourUI: 单例实例如果不存在则返回None
"""
return cls._instance
def __init__(self, parent=None):
"""
初始化行为系统UI
"""
super(BehaviourUI, self).__init__() # 不传递parent参数给BaseUI
self.main_widget = QtWidgets.QWidget(parent) # 在创建main_widget时传递parent
self.main_widget.setObjectName("behaviourMainWidget")
# 设置单例实例
BehaviourUI._instance = self
# 初始化控件、布局和按钮字典
self.controls = {}
self.layouts = {}
self.buttons = {}
self.splitters = {}
# 创建UI组件
self.create_widgets()
self.create_layouts()
self.create_connections()
# 在创建完所有布局后,设置分割器的初始大小和属性
# 使用ui_utils中的函数来设置分割器大小
ui_utils.setup_splitter(self, "main_splitter", [1, 1])
# 设置分割器所有子元素的最小尺寸为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)
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.controls["title_label"].setStyleSheet("font-size: 14px; font-weight: bold; padding: 5px;")
# 主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("behaviourMainSplitter")
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果,更丝滑
# 左侧面板 - Raw Control
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("behaviourLeftPanel")
self.controls["left_panel"].setMinimumWidth(0)
self.controls["left_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 右侧面板 - BlendShapes
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("behaviourRightPanel")
self.controls["right_panel"].setMinimumWidth(0)
self.controls["right_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 搜索框
self.controls["search_input"] = QtWidgets.QLineEdit()
self.controls["search_input"].setObjectName("searchInput")
self.controls["search_input"].setPlaceholderText(LANG.get("search", "搜索..."))
# 控制列表
self.controls["control_list"] = QtWidgets.QListWidget()
self.controls["control_list"].setObjectName("controlList")
self.controls["control_list"].setMinimumWidth(0) # 设置最小宽度为零
# 底部滑块
self.controls["raw_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.controls["raw_slider"].setObjectName("rawSlider")
self.controls["raw_slider"].setMinimum(0)
self.controls["raw_slider"].setMaximum(100)
self.controls["raw_slider"].setValue(0)
self.controls["raw_slider"].setFixedHeight(20)
# 创建滑块布局,包含数值显示和滑块
self.layouts["raw_slider_layout"] = QtWidgets.QHBoxLayout()
self.layouts["raw_slider_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["raw_slider_layout"].setSpacing(2)
# 添加数值显示标签
self.controls["raw_slider_value"] = QtWidgets.QLabel("0.000")
self.controls["raw_slider_value"].setObjectName("rawSliderValue")
self.controls["raw_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.controls["raw_slider_value"].setFixedWidth(40)
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider_value"])
# 添加滑块
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider"])
# 添加"All"勾选框和标签
self.controls["raw_slider_all_check"] = QtWidgets.QCheckBox("All")
self.controls["raw_slider_all_check"].setObjectName("rawSliderAllCheck")
self.layouts["raw_slider_layout"].addWidget(self.controls["raw_slider_all_check"])
# 页码按钮
self.buttons["prev_page"] = QtWidgets.QPushButton("上一页")
self.buttons["prev_page"].setObjectName("prevPageButton")
self.buttons["prev_page"].setIcon(ui_utils.get_icon("arrowLeft.png"))
self.buttons["next_page"] = QtWidgets.QPushButton("下一页")
self.buttons["next_page"].setObjectName("nextPageButton")
self.buttons["next_page"].setIcon(ui_utils.get_icon("arrowRight.png"))
self.buttons["page_all"] = QtWidgets.QPushButton("All")
self.buttons["page_all"].setObjectName("pageAllButton")
self.buttons["page_all"].setCheckable(True)
self.buttons["page_all"].setChecked(True)
self.buttons["page_2"] = QtWidgets.QPushButton("2")
self.buttons["page_2"].setObjectName("page2Button")
self.buttons["page_2"].setCheckable(True)
self.buttons["page_3"] = QtWidgets.QPushButton("3")
self.buttons["page_3"].setObjectName("page3Button")
self.buttons["page_3"].setCheckable(True)
self.buttons["page_4"] = QtWidgets.QPushButton("4")
self.buttons["page_4"].setObjectName("page4Button")
self.buttons["page_4"].setCheckable(True)
self.buttons["page_5"] = QtWidgets.QPushButton("5")
self.buttons["page_5"].setObjectName("page5Button")
self.buttons["page_5"].setCheckable(True)
self.buttons["page_6"] = QtWidgets.QPushButton("6")
self.buttons["page_6"].setObjectName("page6Button")
self.buttons["page_6"].setCheckable(True)
# 左下角Range按钮
self.buttons["range_plus"] = QtWidgets.QPushButton("Range +")
self.buttons["range_plus"].setObjectName("rangePlusButton")
self.buttons["range_plus"].setIcon(ui_utils.get_icon("behaviour.png"))
self.buttons["range_minus"] = QtWidgets.QPushButton("Range -")
self.buttons["range_minus"].setObjectName("rangeMinusButton")
self.buttons["range_minus"].setIcon(ui_utils.get_icon("behaviour.png"))
# 右侧面板控件 - Related BlendShapes
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("Related BlendShapes [000]")
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
self.controls["blendshapes_group"].setMinimumWidth(0) # 设置最小宽度为零
self.controls["blendshapes_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# BlendShapes列表
self.controls["blendshapes_list"] = QtWidgets.QListWidget()
self.controls["blendshapes_list"].setObjectName("blendshapesList")
self.controls["blendshapes_list"].setMinimumWidth(0) # 设置最小宽度为零
self.controls["blendshapes_list"].setMinimumHeight(100) # 设置最小高度,确保列表可见
self.controls["blendshapes_list"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 底部滑块
self.controls["bs_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.controls["bs_slider"].setObjectName("bsSlider")
self.controls["bs_slider"].setMinimum(0)
self.controls["bs_slider"].setMaximum(100)
self.controls["bs_slider"].setValue(0)
# 创建BS滑块布局包含数值显示和滑块
self.layouts["bs_slider_layout"] = QtWidgets.QHBoxLayout()
self.layouts["bs_slider_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["bs_slider_layout"].setSpacing(2)
# 添加数值显示标签
self.controls["bs_slider_value"] = QtWidgets.QLabel("0.000")
self.controls["bs_slider_value"].setObjectName("bsSliderValue")
self.controls["bs_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.controls["bs_slider_value"].setFixedWidth(40)
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider_value"])
# 添加滑块
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider"])
# 添加"All"勾选框和标签
self.controls["bs_slider_all_check"] = QtWidgets.QCheckBox("All")
self.controls["bs_slider_all_check"].setObjectName("bsSliderAllCheck")
self.layouts["bs_slider_layout"].addWidget(self.controls["bs_slider_all_check"])
# BlendShape操作按钮
self.buttons["flip_target"] = QtWidgets.QPushButton("Flip Target")
self.buttons["flip_target"].setObjectName("flipTargetButton")
self.buttons["flip_target"].setIcon(ui_utils.get_icon("mirrorL.png"))
self.buttons["flip_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["mirror_target"] = QtWidgets.QPushButton("Mirror Target")
self.buttons["mirror_target"].setObjectName("mirrorTargetButton")
self.buttons["mirror_target"].setIcon(ui_utils.get_icon("mirror.png"))
self.buttons["mirror_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["find_flip_target"] = QtWidgets.QPushButton("Find Flip Target")
self.buttons["find_flip_target"].setObjectName("findFlipTargetButton")
self.buttons["find_flip_target"].setIcon(ui_utils.get_icon("mirrorR.png"))
self.buttons["find_flip_target"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["add_blendshape"] = QtWidgets.QPushButton("Add BlendShape")
self.buttons["add_blendshape"].setObjectName("addBlendshapeButton")
self.buttons["add_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
self.buttons["add_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["delete_blendshape"] = QtWidgets.QPushButton("Delete BlendShape")
self.buttons["delete_blendshape"].setObjectName("deleteBlendshapeButton")
self.buttons["delete_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
self.buttons["delete_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["batch_blendshape"] = QtWidgets.QPushButton("Batch BlendShape")
self.buttons["batch_blendshape"].setObjectName("batchBlendshapeButton")
self.buttons["batch_blendshape"].setIcon(ui_utils.get_icon("blendShape.png"))
self.buttons["batch_blendshape"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["rebuild_select"] = QtWidgets.QPushButton("Rebuild Select")
self.buttons["rebuild_select"].setObjectName("rebuildSelectButton")
self.buttons["rebuild_select"].setIcon(ui_utils.get_icon("loading.png"))
self.buttons["rebuild_select"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["reposition_joints"] = QtWidgets.QPushButton("Reposition Joints")
self.buttons["reposition_joints"].setObjectName("repositionJointsButton")
self.buttons["reposition_joints"].setIcon(ui_utils.get_icon("loading.png"))
self.buttons["reposition_joints"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons["blend_select"] = QtWidgets.QPushButton("Blend Select")
self.buttons["blend_select"].setObjectName("blendSelectButton")
self.buttons["blend_select"].setIcon(ui_utils.get_icon("loading.png"))
self.buttons["blend_select"].setMinimumHeight(25) # 设置最小高度,确保按钮可见
# 右侧Range按钮
self.buttons["bs_range_plus"] = QtWidgets.QPushButton("Range +")
self.buttons["bs_range_plus"].setObjectName("bsRangePlusButton")
self.buttons["bs_range_plus"].setIcon(ui_utils.get_icon("behaviour.png"))
self.buttons["bs_range_minus"] = QtWidgets.QPushButton("Range -")
self.buttons["bs_range_minus"].setObjectName("bsRangeMinusButton")
self.buttons["bs_range_minus"].setIcon(ui_utils.get_icon("behaviour.png"))
# 底部标签页按钮
self.buttons["tab_psd"] = QtWidgets.QPushButton("PSD")
self.buttons["tab_psd"].setIcon(ui_utils.get_icon("psd.png"))
self.buttons["tab_psd"].setObjectName("tabPsdButton")
self.buttons["tab_psd"].setCheckable(True)
self.buttons["tab_bse"] = QtWidgets.QPushButton("BSE")
self.buttons["tab_bse"].setIcon(ui_utils.get_icon("blendShape.png"))
self.buttons["tab_bse"].setObjectName("tabBseButton")
self.buttons["tab_bse"].setCheckable(True)
self.buttons["tab_key"] = QtWidgets.QPushButton("KEY")
self.buttons["tab_key"].setIcon(ui_utils.get_icon("setKeyOnAnim.png"))
self.buttons["tab_key"].setObjectName("tabKeyButton")
self.buttons["tab_key"].setCheckable(True)
self.buttons["tab_mir"] = QtWidgets.QPushButton("MIR")
self.buttons["tab_mir"].setIcon(ui_utils.get_icon("mirrorR.png"))
self.buttons["tab_mir"].setObjectName("tabMirButton")
self.buttons["tab_mir"].setCheckable(True)
self.buttons["tab_ark"] = QtWidgets.QPushButton("ARK")
self.buttons["tab_ark"].setIcon(ui_utils.get_icon("ARKit52.png"))
self.buttons["tab_ark"].setObjectName("tabArkButton")
self.buttons["tab_ark"].setCheckable(True)
self.buttons["tab_ctr"] = QtWidgets.QPushButton("CTR")
self.buttons["tab_ctr"].setIcon(ui_utils.get_icon("ctrl_hide.png"))
self.buttons["tab_ctr"].setObjectName("tabCtrButton")
self.buttons["tab_ctr"].setCheckable(True)
# 底部主滑块
self.controls["bottom_main_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.controls["bottom_main_slider"].setObjectName("bottomMainSlider")
self.controls["bottom_main_slider"].setMinimum(0)
self.controls["bottom_main_slider"].setMaximum(100)
self.controls["bottom_main_slider"].setValue(0)
self.controls["bottom_main_slider"].setFixedHeight(20)
# 底部主滑块布局包含数值显示和All勾选框
self.layouts["bottom_slider_layout"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_slider_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["bottom_slider_layout"].setSpacing(2)
# 添加数值显示标签
self.controls["bottom_slider_value"] = QtWidgets.QLabel("0.000")
self.controls["bottom_slider_value"].setObjectName("bottomSliderValue")
self.controls["bottom_slider_value"].setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.controls["bottom_slider_value"].setFixedWidth(40)
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_slider_value"])
# 添加滑块
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_main_slider"])
# 添加"All"勾选框
self.controls["bottom_slider_all_check"] = QtWidgets.QCheckBox("All")
self.controls["bottom_slider_all_check"].setObjectName("bottomSliderAllCheck")
self.layouts["bottom_slider_layout"].addWidget(self.controls["bottom_slider_all_check"])
# 底部功能按钮
self.buttons["reset_default_expression"] = QtWidgets.QPushButton("Reset Default Expression")
self.buttons["reset_default_expression"].setIcon(ui_utils.get_icon("reset.png"))
self.buttons["reset_default_expression"].setObjectName("resetDefaultExpressionButton")
self.buttons["find_select_expression"] = QtWidgets.QPushButton("Find Select Expression")
self.buttons["find_select_expression"].setIcon(ui_utils.get_icon("expressions_current.png"))
self.buttons["find_select_expression"].setObjectName("findSelectExpressionButton")
self.buttons["write_current_expressions"] = QtWidgets.QPushButton("Write Current Expressions")
self.buttons["write_current_expressions"].setIcon(ui_utils.get_icon("expression.png"))
self.buttons["write_current_expressions"].setObjectName("writeCurrentExpressionsButton")
self.buttons["controller_find"] = QtWidgets.QPushButton("Controller Find")
self.buttons["controller_find"].setIcon(ui_utils.get_icon("controller.png"))
self.buttons["controller_find"].setObjectName("controllerFindButton")
self.buttons["select_associated_joint"] = QtWidgets.QPushButton("Select Associated Joint")
self.buttons["select_associated_joint"].setIcon(ui_utils.get_icon("out_joint.png"))
self.buttons["select_associated_joint"].setObjectName("selectAssociatedJointButton")
self.buttons["write_find_mirror"] = QtWidgets.QPushButton("Write Find Mirror")
self.buttons["write_find_mirror"].setIcon(ui_utils.get_icon("mirror.png"))
self.buttons["write_find_mirror"].setObjectName("writeFindMirrorButton")
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建行为系统UI布局
包括主布局、左右面板布局等
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["main_layout"].setSpacing(0)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("behaviourMainSplitter")
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果,更丝滑
# 添加主分割器
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"], 1) # 设置伸缩因子为1使其占据剩余空间
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("behaviourLeftPanel")
self.controls["left_panel"].setMinimumWidth(0)
self.controls["left_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("behaviourRightPanel")
self.controls["right_panel"].setMinimumWidth(0)
self.controls["right_panel"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 将左右面板添加到分割器
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["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# 左侧面板控件 - Raw Control
self.controls["raw_control_group"] = QtWidgets.QGroupBox("Raw Control")
self.controls["raw_control_group"].setObjectName("rawControlGroup")
self.controls["raw_control_group"].setMinimumWidth(0) # 设置最小宽度为零
self.controls["raw_control_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 左侧面板控件布局
self.layouts["raw_control_layout"] = QtWidgets.QVBoxLayout()
self.layouts["raw_control_layout"].setContentsMargins(2, 2, 2, 2)
self.layouts["raw_control_layout"].setSpacing(2)
self.controls["raw_control_group"].setLayout(self.layouts["raw_control_layout"])
# 添加控制列表到Raw Control布局
self.layouts["raw_control_layout"].addWidget(self.controls["control_list"])
# 左侧滑块布局
self.layouts["raw_control_layout"].addLayout(self.layouts["raw_slider_layout"])
# 范围调整按钮布局
self.layouts["range_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["range_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["range_buttons_layout"].setSpacing(2)
# 设置Range按钮的策略使其均等撑满一行
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.buttons["range_plus"].setSizePolicy(size_policy)
self.buttons["range_minus"].setSizePolicy(size_policy)
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_plus"])
self.layouts["range_buttons_layout"].addWidget(self.buttons["range_minus"])
# 添加范围按钮布局到Raw Control布局
self.layouts["raw_control_layout"].addLayout(self.layouts["range_buttons_layout"])
# 页码按钮布局
self.layouts["page_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["page_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["page_buttons_layout"].setSpacing(2)
# 设置页码按钮的策略,使其均等撑满一行
for button_name in ["prev_page", "next_page", "page_all", "page_2", "page_3", "page_4", "page_5", "page_6"]:
if button_name in self.buttons:
self.buttons[button_name].setSizePolicy(size_policy)
# 添加页码按钮到布局
for button_name in ["prev_page", "next_page", "page_all", "page_2", "page_3", "page_4", "page_5", "page_6"]:
if button_name in self.buttons:
self.layouts["page_buttons_layout"].addWidget(self.buttons[button_name])
# 添加页码按钮布局到Raw Control布局
self.layouts["raw_control_layout"].addLayout(self.layouts["page_buttons_layout"])
# 添加Raw Control组到左侧面板
self.layouts["left_layout"].addWidget(self.controls["raw_control_group"])
# 右侧面板控件 - Related BlendShapes
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("Related BlendShapes")
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
self.controls["blendshapes_group"].setMinimumWidth(0) # 设置最小宽度为零
self.controls["blendshapes_group"].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 右侧面板控件布局
self.layouts["blendshapes_layout"] = QtWidgets.QVBoxLayout()
self.layouts["blendshapes_layout"].setContentsMargins(2, 2, 2, 2)
self.layouts["blendshapes_layout"].setSpacing(2)
self.controls["blendshapes_group"].setLayout(self.layouts["blendshapes_layout"])
# 添加BlendShapes列表到BlendShapes布局
self.layouts["blendshapes_layout"].addWidget(self.controls["blendshapes_list"], 1) # 设置伸缩因子为1使其占据更多空间
# 右侧滑块布局
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_slider_layout"])
# BS范围调整按钮布局
self.layouts["bs_range_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["bs_range_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["bs_range_buttons_layout"].setSpacing(2)
# 设置BS Range按钮的策略使其均等撑满一行
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.buttons["bs_range_plus"].setSizePolicy(size_policy)
self.buttons["bs_range_minus"].setSizePolicy(size_policy)
self.layouts["bs_range_buttons_layout"].addWidget(self.buttons["bs_range_plus"])
self.layouts["bs_range_buttons_layout"].addWidget(self.buttons["bs_range_minus"])
# 添加BS范围按钮布局到BlendShapes布局
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_range_buttons_layout"])
# 为所有按钮设置统一的大小策略
for button_name in ["flip_target", "mirror_target", "find_flip_target",
"add_blendshape", "delete_blendshape", "batch_blendshape",
"rebuild_select", "reposition_joints", "blend_select"]:
if button_name in self.buttons:
self.buttons[button_name].setMinimumWidth(0)
self.buttons[button_name].setMinimumHeight(25) # 设置最小高度,确保按钮可见
self.buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# BlendShape操作按钮网格
self.layouts["bs_buttons_grid"] = QtWidgets.QGridLayout()
self.layouts["bs_buttons_grid"].setContentsMargins(0, 0, 0, 0)
self.layouts["bs_buttons_grid"].setSpacing(2)
# 添加按钮到网格
self.layouts["bs_buttons_grid"].addWidget(self.buttons["flip_target"], 0, 0)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["mirror_target"], 0, 1)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["find_flip_target"], 0, 2)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["add_blendshape"], 1, 0)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["delete_blendshape"], 1, 1)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["batch_blendshape"], 1, 2)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["rebuild_select"], 2, 0)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["reposition_joints"], 2, 1)
self.layouts["bs_buttons_grid"].addWidget(self.buttons["blend_select"], 2, 2)
# 添加按钮网格到BlendShapes布局
self.layouts["blendshapes_layout"].addLayout(self.layouts["bs_buttons_grid"])
# 添加BlendShapes组到右侧面板
self.layouts["right_layout"].addWidget(self.controls["blendshapes_group"], 1) # 设置伸缩因子为1使其占据更多空间
# 底部标签页按钮行
self.layouts["tab_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["tab_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["tab_buttons_layout"].setSpacing(0)
# 设置标签页按钮的策略,使其均等撑满一行
for button_name in ["tab_psd", "tab_bse", "tab_key", "tab_mir", "tab_ark", "tab_ctr"]:
if button_name in self.buttons:
self.buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.layouts["tab_buttons_layout"].addWidget(self.buttons[button_name])
# 添加标签页按钮行到主布局
self.layouts["main_layout"].addLayout(self.layouts["tab_buttons_layout"])
# 底部按钮布局
self.layouts["bottom_buttons_layout"] = QtWidgets.QVBoxLayout()
self.layouts["bottom_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["bottom_buttons_layout"].setSpacing(5)
# 第一行按钮
self.layouts["bottom_buttons_row1"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_buttons_row1"].setContentsMargins(0, 0, 0, 0)
self.layouts["bottom_buttons_row1"].setSpacing(5)
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["reset_default_expression"])
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["find_select_expression"])
self.layouts["bottom_buttons_row1"].addWidget(self.buttons["write_current_expressions"])
# 第二行按钮
self.layouts["bottom_buttons_row2"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_buttons_row2"].setContentsMargins(0, 0, 0, 0)
self.layouts["bottom_buttons_row2"].setSpacing(5)
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["controller_find"])
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["select_associated_joint"])
self.layouts["bottom_buttons_row2"].addWidget(self.buttons["write_find_mirror"])
# 将两行按钮添加到底部按钮布局
self.layouts["bottom_buttons_layout"].addLayout(self.layouts["bottom_buttons_row1"])
self.layouts["bottom_buttons_layout"].addLayout(self.layouts["bottom_buttons_row2"])
# 添加底部按钮布局到主布局
self.layouts["main_layout"].addLayout(self.layouts["bottom_buttons_layout"])
# 底部主滑块布局
self.layouts["main_layout"].addLayout(self.layouts["bottom_slider_layout"])
#======================================= CONNECTION =====================================
def create_connections(self):
"""
创建信号连接
连接按钮点击事件和其他UI事件
"""
# 创建信号映射字典
signal_mapping = {
'buttons': {
# 底部标签页按钮
'tab_psd': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(0)},
'tab_bse': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(1)},
'tab_key': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(2)},
'tab_mir': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(3)},
'tab_ark': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(4)},
'tab_ctr': {'signal': 'clicked', 'handler': lambda: utils_behaviour.switch_tab(5)},
# 功能按钮
'flip_target': {'signal': 'clicked', 'handler': utils_behaviour.flip_target},
'mirror_target': {'signal': 'clicked', 'handler': utils_behaviour.mirror_target},
'find_flip_target': {'signal': 'clicked', 'handler': utils_behaviour.find_flip_target},
'add_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.add_blendshape},
'delete_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.delete_blendshape},
'batch_blendshape': {'signal': 'clicked', 'handler': utils_behaviour.batch_blendshape},
'rebuild_select': {'signal': 'clicked', 'handler': utils_behaviour.rebuild_select},
'reposition_joints': {'signal': 'clicked', 'handler': utils_behaviour.reposition_joints},
'blend_select': {'signal': 'clicked', 'handler': utils_behaviour.blend_select},
'reset_default_expression': {'signal': 'clicked', 'handler': utils_behaviour.reset_default_expression},
'find_select_expression': {'signal': 'clicked', 'handler': utils_behaviour.find_select_expression},
'write_current_expressions': {'signal': 'clicked', 'handler': utils_behaviour.write_current_expressions},
'controller_find': {'signal': 'clicked', 'handler': utils_behaviour.controller_find},
'select_associated_joint': {'signal': 'clicked', 'handler': utils_behaviour.select_associated_joint},
'write_find_mirror': {'signal': 'clicked', 'handler': utils_behaviour.write_find_mirror},
# 范围按钮
'range_plus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_range(0.1)},
'range_minus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_range(-0.1)},
'bs_range_plus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_bs_range(0.1)},
'bs_range_minus': {'signal': 'clicked', 'handler': lambda: utils_behaviour.adjust_bs_range(-0.1)},
},
'controls': {
# 滑块控件
'raw_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_raw_slider_changed},
'bs_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_bs_slider_changed},
'bottom_main_slider': {'signal': 'valueChanged', 'handler': utils_behaviour.on_bottom_slider_changed},
# 列表控件
'control_list': {'signal': 'itemSelectionChanged', 'handler': utils_behaviour.on_control_selection_changed},
'blendshapes_list': {'signal': 'itemSelectionChanged', 'handler': utils_behaviour.on_blendshape_selection_changed},
}
}
# 使用ui_utils中的函数连接信号
ui_utils.connect_ui_signals(self, signal_mapping)
# 连接Maya选择变化事件
ui_utils.connect_maya_selection_changed(self, lambda: utils_behaviour.on_selection_changed(self), self.main_widget)