#!/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.load_icon("arrowLeft.png")) self.buttons["next_page"] = QtWidgets.QPushButton("下一页") self.buttons["next_page"].setObjectName("nextPageButton") self.buttons["next_page"].setIcon(ui_utils.load_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.load_icon("behaviour.png")) self.buttons["range_minus"] = QtWidgets.QPushButton("Range -") self.buttons["range_minus"].setObjectName("rangeMinusButton") self.buttons["range_minus"].setIcon(ui_utils.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_icon("behaviour.png")) # 底部标签页按钮 self.buttons["tab_psd"] = QtWidgets.QPushButton("PSD") self.buttons["tab_psd"].setIcon(ui_utils.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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.load_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)