update
This commit is contained in:
@@ -60,251 +60,76 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
继承自BaseUI类,实现绑定系统相关的UI功能
|
||||
"""
|
||||
#======================================= FUNCTIONS ======================================
|
||||
def on_show_event(self, event):
|
||||
def connect_ui_signals(self):
|
||||
"""
|
||||
显示事件处理
|
||||
当面板显示时重置分割器大小
|
||||
连接UI信号和槽
|
||||
设置UI控件的事件处理函数
|
||||
"""
|
||||
self.reset_splitter_sizes()
|
||||
super(RiggingUI, self).showEvent(event)
|
||||
# 创建信号映射字典
|
||||
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},
|
||||
},
|
||||
'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)
|
||||
|
||||
# 连接关节属性编辑控件
|
||||
if hasattr(self, 'joint_name_edit'):
|
||||
self.joint_name_edit.editingFinished.connect(lambda: utils_rigging.handle_joint_name_changed(self.joint_name_edit))
|
||||
|
||||
# 关节位置编辑
|
||||
if hasattr(self, 'joint_pos_x_spin'):
|
||||
self.joint_pos_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(0, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
|
||||
if hasattr(self, 'joint_pos_y_spin'):
|
||||
self.joint_pos_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(1, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
|
||||
if hasattr(self, 'joint_pos_z_spin'):
|
||||
self.joint_pos_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_position_changed(2, [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin]))
|
||||
|
||||
# 关节旋转编辑
|
||||
if hasattr(self, 'joint_rot_x_spin'):
|
||||
self.joint_rot_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(0, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
|
||||
if hasattr(self, 'joint_rot_y_spin'):
|
||||
self.joint_rot_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(1, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
|
||||
if hasattr(self, 'joint_rot_z_spin'):
|
||||
self.joint_rot_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_rotation_changed(2, [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin]))
|
||||
|
||||
# 关节缩放编辑
|
||||
if hasattr(self, 'joint_scale_x_spin'):
|
||||
self.joint_scale_x_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(0, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
|
||||
if hasattr(self, 'joint_scale_y_spin'):
|
||||
self.joint_scale_y_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(1, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
|
||||
if hasattr(self, 'joint_scale_z_spin'):
|
||||
self.joint_scale_z_spin.valueChanged.connect(lambda val: utils_rigging.handle_joint_scale_changed(2, [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin]))
|
||||
|
||||
# 关节属性应用和重置按钮
|
||||
if "apply_joint_props_btn" in self.buttons:
|
||||
pos_widgets = [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin] if all(hasattr(self, attr) for attr in ['joint_pos_x_spin', 'joint_pos_y_spin', 'joint_pos_z_spin']) else None
|
||||
rot_widgets = [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin] if all(hasattr(self, attr) for attr in ['joint_rot_x_spin', 'joint_rot_y_spin', 'joint_rot_z_spin']) else None
|
||||
scale_widgets = [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin] if all(hasattr(self, attr) for attr in ['joint_scale_x_spin', 'joint_scale_y_spin', 'joint_scale_z_spin']) else None
|
||||
self.buttons["apply_joint_props_btn"].clicked.connect(lambda: utils_rigging.apply_joint_properties_from_ui(pos_widgets, rot_widgets, scale_widgets))
|
||||
|
||||
if "reset_joint_props_btn" in self.buttons:
|
||||
pos_widgets = [self.joint_pos_x_spin, self.joint_pos_y_spin, self.joint_pos_z_spin] if all(hasattr(self, attr) for attr in ['joint_pos_x_spin', 'joint_pos_y_spin', 'joint_pos_z_spin']) else None
|
||||
rot_widgets = [self.joint_rot_x_spin, self.joint_rot_y_spin, self.joint_rot_z_spin] if all(hasattr(self, attr) for attr in ['joint_rot_x_spin', 'joint_rot_y_spin', 'joint_rot_z_spin']) else None
|
||||
scale_widgets = [self.joint_scale_x_spin, self.joint_scale_y_spin, self.joint_scale_z_spin] if all(hasattr(self, attr) for attr in ['joint_scale_x_spin', 'joint_scale_y_spin', 'joint_scale_z_spin']) else None
|
||||
self.buttons["reset_joint_props_btn"].clicked.connect(lambda: utils_rigging.reset_joint_properties_ui(pos_widgets, rot_widgets, scale_widgets))
|
||||
|
||||
# 使用Maya的脚本任务来监听选择变化
|
||||
ui_utils.connect_maya_selection_changed(self, utils_rigging.on_selection_changed)
|
||||
|
||||
def reset_splitter_sizes(self):
|
||||
"""
|
||||
重置分割器大小,确保左右栏宽度均等
|
||||
"""
|
||||
if self.splitters["main_splitter"]:
|
||||
width = self.splitters["main_splitter"].width()
|
||||
self.splitters["main_splitter"].setSizes([width // 2, width // 2])
|
||||
|
||||
def on_splitter_moved(self, pos, index):
|
||||
"""
|
||||
分割器移动事件处理
|
||||
记录当前分割器位置
|
||||
"""
|
||||
utils_rigging.update_splitter_position(self.splitters["main_splitter"])
|
||||
|
||||
# 左侧面板 - 骨骼列表操作
|
||||
def add_joint(self):
|
||||
"""
|
||||
添加关节
|
||||
"""
|
||||
utils_rigging.add_joint(self.controls["skeleton_list"])
|
||||
|
||||
def remove_joint(self):
|
||||
"""
|
||||
移除关节
|
||||
"""
|
||||
utils_rigging.remove_joint(self.controls["skeleton_list"])
|
||||
|
||||
def duplicate_joint(self):
|
||||
"""
|
||||
复制关节
|
||||
"""
|
||||
utils_rigging.duplicate_joint(self.controls["skeleton_list"])
|
||||
|
||||
def on_joint_selection_changed(self):
|
||||
"""
|
||||
关节选择变化事件
|
||||
更新关节属性面板
|
||||
"""
|
||||
utils_rigging.update_joint_properties(
|
||||
self.controls["skeleton_list"],
|
||||
self.controls["joint_name_input"],
|
||||
self.controls["joint_x_input"],
|
||||
self.controls["joint_y_input"],
|
||||
self.controls["joint_z_input"],
|
||||
self.controls["joint_rx_input"],
|
||||
self.controls["joint_ry_input"],
|
||||
self.controls["joint_rz_input"],
|
||||
self.controls["joint_sx_input"],
|
||||
self.controls["joint_sy_input"],
|
||||
self.controls["joint_sz_input"]
|
||||
)
|
||||
|
||||
# 左侧面板 - 控制器列表操作
|
||||
def add_controller(self):
|
||||
"""
|
||||
添加控制器
|
||||
"""
|
||||
utils_rigging.add_controller(self.controls["controller_list"])
|
||||
|
||||
def remove_controller(self):
|
||||
"""
|
||||
移除控制器
|
||||
"""
|
||||
utils_rigging.remove_controller(self.controls["controller_list"])
|
||||
|
||||
def duplicate_controller(self):
|
||||
"""
|
||||
复制控制器
|
||||
"""
|
||||
utils_rigging.duplicate_controller(self.controls["controller_list"])
|
||||
|
||||
def on_controller_selection_changed(self):
|
||||
"""
|
||||
控制器选择变化事件
|
||||
更新控制器属性
|
||||
"""
|
||||
utils_rigging.update_controller_properties(self.controls["controller_list"])
|
||||
|
||||
# 右侧面板 - 关节属性
|
||||
def on_joint_name_changed(self):
|
||||
"""
|
||||
关节名称变化事件
|
||||
"""
|
||||
utils_rigging.update_joint_name(
|
||||
self.controls["skeleton_list"],
|
||||
self.controls["joint_name_input"]
|
||||
)
|
||||
|
||||
def on_joint_position_changed(self, axis):
|
||||
"""
|
||||
关节位置变化事件
|
||||
"""
|
||||
utils_rigging.update_joint_position(
|
||||
self.controls["skeleton_list"],
|
||||
axis,
|
||||
self.controls[f"joint_{axis}_input"]
|
||||
)
|
||||
|
||||
def on_joint_rotation_changed(self, axis):
|
||||
"""
|
||||
关节旋转变化事件
|
||||
"""
|
||||
utils_rigging.update_joint_rotation(
|
||||
self.controls["skeleton_list"],
|
||||
axis,
|
||||
self.controls[f"joint_r{axis}_input"]
|
||||
)
|
||||
|
||||
def on_joint_scale_changed(self, axis):
|
||||
"""
|
||||
关节缩放变化事件
|
||||
"""
|
||||
utils_rigging.update_joint_scale(
|
||||
self.controls["skeleton_list"],
|
||||
axis,
|
||||
self.controls[f"joint_s{axis}_input"]
|
||||
)
|
||||
|
||||
def apply_joint_properties(self):
|
||||
"""
|
||||
应用关节属性
|
||||
"""
|
||||
utils_rigging.apply_joint_properties(
|
||||
self.controls["skeleton_list"],
|
||||
self.controls["joint_name_input"],
|
||||
self.controls["joint_x_input"],
|
||||
self.controls["joint_y_input"],
|
||||
self.controls["joint_z_input"],
|
||||
self.controls["joint_rx_input"],
|
||||
self.controls["joint_ry_input"],
|
||||
self.controls["joint_rz_input"],
|
||||
self.controls["joint_sx_input"],
|
||||
self.controls["joint_sy_input"],
|
||||
self.controls["joint_sz_input"]
|
||||
)
|
||||
|
||||
def reset_joint_properties(self):
|
||||
"""
|
||||
重置关节属性
|
||||
"""
|
||||
utils_rigging.reset_joint_properties(
|
||||
self.controls["skeleton_list"],
|
||||
self.controls["joint_name_input"],
|
||||
self.controls["joint_x_input"],
|
||||
self.controls["joint_y_input"],
|
||||
self.controls["joint_z_input"],
|
||||
self.controls["joint_rx_input"],
|
||||
self.controls["joint_ry_input"],
|
||||
self.controls["joint_rz_input"],
|
||||
self.controls["joint_sx_input"],
|
||||
self.controls["joint_sy_input"],
|
||||
self.controls["joint_sz_input"]
|
||||
)
|
||||
|
||||
# 右侧面板 - 绑定工具
|
||||
def create_binding(self):
|
||||
"""
|
||||
创建绑定
|
||||
"""
|
||||
utils_rigging.create_binding()
|
||||
|
||||
def copy_skin(self):
|
||||
"""
|
||||
复制蒙皮
|
||||
"""
|
||||
utils_rigging.copy_skin()
|
||||
|
||||
def mirror_skin(self):
|
||||
"""
|
||||
镜像蒙皮
|
||||
"""
|
||||
utils_rigging.mirror_skin()
|
||||
|
||||
def paint_weights(self):
|
||||
"""
|
||||
绘制权重
|
||||
"""
|
||||
utils_rigging.paint_weights()
|
||||
|
||||
# 底部工具面板 - DNA操作
|
||||
def import_dna(self):
|
||||
"""
|
||||
导入DNA
|
||||
"""
|
||||
utils_rigging.import_dna()
|
||||
|
||||
def export_dna(self):
|
||||
"""
|
||||
导出DNA
|
||||
"""
|
||||
utils_rigging.export_dna()
|
||||
|
||||
def calibrate_dna(self):
|
||||
"""
|
||||
校准DNA
|
||||
"""
|
||||
utils_rigging.calibrate_dna()
|
||||
|
||||
# 底部工具面板 - 骨骼工具
|
||||
def import_skeleton(self):
|
||||
"""
|
||||
导入骨骼
|
||||
"""
|
||||
utils_rigging.import_skeleton()
|
||||
|
||||
def export_skeleton(self):
|
||||
"""
|
||||
导出骨骼
|
||||
"""
|
||||
utils_rigging.export_skeleton()
|
||||
|
||||
def calibrate_skeleton(self):
|
||||
"""
|
||||
校准骨骼
|
||||
"""
|
||||
utils_rigging.calibrate_skeleton()
|
||||
|
||||
# 底部工具面板 - 绑定工具
|
||||
def generate_controllers(self):
|
||||
"""
|
||||
生成控制器
|
||||
"""
|
||||
utils_rigging.generate_controllers()
|
||||
|
||||
def generate_body(self):
|
||||
"""
|
||||
生成身体
|
||||
"""
|
||||
utils_rigging.generate_body()
|
||||
|
||||
def clean_rigging(self):
|
||||
"""
|
||||
清理绑定
|
||||
"""
|
||||
utils_rigging.clean_rigging()
|
||||
|
||||
#========================================== INIT ========================================
|
||||
def __init__(self):
|
||||
"""
|
||||
@@ -313,6 +138,14 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
"""
|
||||
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")
|
||||
@@ -320,7 +153,7 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
# 初始化UI
|
||||
self.create_widgets()
|
||||
self.create_layouts()
|
||||
self.create_connections()
|
||||
self.connect_ui_signals()
|
||||
|
||||
#========================================= WIDGET =======================================
|
||||
def create_widgets(self):
|
||||
@@ -335,36 +168,244 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
|
||||
|
||||
# 左侧面板
|
||||
self.controls["left_panel"] = QtWidgets.QWidget()
|
||||
self.controls["left_panel"].setObjectName("riggingLeftPanel")
|
||||
# 创建主分割器
|
||||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
|
||||
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
|
||||
|
||||
# 右侧面板
|
||||
self.controls["right_panel"] = QtWidgets.QWidget()
|
||||
self.controls["right_panel"].setObjectName("riggingRightPanel")
|
||||
# 1. Presets 面板
|
||||
self.controls["presets_panel"] = QtWidgets.QWidget()
|
||||
self.controls["presets_panel"].setObjectName("presetsPanel")
|
||||
|
||||
# 左侧面板控件 - 骨骼列表
|
||||
self.controls["skeleton_group"] = QtWidgets.QGroupBox("Skeleton [000]")
|
||||
self.controls["skeleton_group"].setObjectName("skeletonGroup")
|
||||
# Presets 组
|
||||
self.controls["presets_group"] = QtWidgets.QGroupBox(LANG.get("presets", "Presets"))
|
||||
self.controls["presets_group"].setObjectName("presetsGroup")
|
||||
|
||||
# 骨骼列表
|
||||
self.controls["skeleton_list"] = QtWidgets.QListWidget()
|
||||
self.controls["skeleton_list"].setObjectName("skeletonList")
|
||||
# 创建预设显示区域
|
||||
self.controls["presets_scroll_area"] = QtWidgets.QScrollArea()
|
||||
self.controls["presets_scroll_area"].setWidgetResizable(True)
|
||||
self.controls["presets_scroll_area"].setObjectName("presetsScrollArea")
|
||||
|
||||
# 添加测试项目
|
||||
for i in range(5):
|
||||
item = QtWidgets.QListWidgetItem(f"Joint_{i}")
|
||||
self.controls["skeleton_list"].addItem(item)
|
||||
# 预设内容区域
|
||||
self.controls["presets_content"] = QtWidgets.QWidget()
|
||||
self.controls["presets_content"].setObjectName("presetsContent")
|
||||
|
||||
# 骨骼操作按钮
|
||||
self.buttons["add_joint"] = QtWidgets.QPushButton(LANG.get("add_joint", "添加关节"))
|
||||
self.buttons["add_joint"].setObjectName("addJointButton")
|
||||
# 预设流布局
|
||||
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)
|
||||
|
||||
self.buttons["remove_joint"] = QtWidgets.QPushButton(LANG.get("remove_joint", "移除关节"))
|
||||
self.buttons["remove_joint"].setObjectName("removeJointButton")
|
||||
# 添加测试预设项
|
||||
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.buttons["duplicate_joint"] = QtWidgets.QPushButton(LANG.get("duplicate_joint", "复制关节"))
|
||||
self.buttons["duplicate_joint"].setObjectName("duplicateJointButton")
|
||||
# 设置滚动区域内容
|
||||
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]")
|
||||
@@ -546,291 +587,126 @@ class RiggingUI(ui_utils.BaseUI):
|
||||
创建绑定系统UI布局
|
||||
组织控件的排列和层次结构
|
||||
"""
|
||||
# 主布局
|
||||
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
|
||||
self.layouts["main_layout"].setContentsMargins(2, 2, 2, 2)
|
||||
self.layouts["main_layout"].setSpacing(2)
|
||||
# 创建主布局
|
||||
main_layout = QtWidgets.QVBoxLayout(self.main_widget)
|
||||
main_layout.setContentsMargins(5, 5, 5, 5)
|
||||
main_layout.setSpacing(5)
|
||||
|
||||
# 添加标题标签
|
||||
self.layouts["main_layout"].addWidget(self.controls["title_label"])
|
||||
# 添加标题
|
||||
main_layout.addWidget(self.controls["title_label"])
|
||||
|
||||
# 创建主分割器
|
||||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
|
||||
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
|
||||
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
|
||||
# 添加主分割器到主布局
|
||||
main_layout.addWidget(self.splitters["main_splitter"])
|
||||
|
||||
# 左侧面板布局
|
||||
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)
|
||||
# 1. Presets 面板布局
|
||||
presets_layout = QtWidgets.QVBoxLayout(self.controls["presets_panel"])
|
||||
presets_layout.setContentsMargins(0, 0, 0, 0)
|
||||
presets_layout.setSpacing(5)
|
||||
|
||||
# 骨骼组布局
|
||||
self.layouts["skeleton_group_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_group"])
|
||||
self.layouts["skeleton_group_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["skeleton_group_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)
|
||||
|
||||
# 骨骼列表
|
||||
self.layouts["skeleton_group_layout"].addWidget(self.controls["skeleton_list"])
|
||||
# 添加预设滚动区域
|
||||
presets_group_layout.addWidget(self.controls["presets_scroll_area"])
|
||||
|
||||
# 骨骼操作按钮行
|
||||
self.layouts["skeleton_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["skeleton_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["skeleton_buttons_layout"].setSpacing(2)
|
||||
# 添加预设底部滑块布局
|
||||
presets_group_layout.addLayout(self.controls["presets_slider_layout"])
|
||||
|
||||
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["add_joint"])
|
||||
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["remove_joint"])
|
||||
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["duplicate_joint"])
|
||||
# 添加Presets组到Presets面板
|
||||
presets_layout.addWidget(self.controls["presets_group"])
|
||||
|
||||
self.layouts["skeleton_group_layout"].addLayout(self.layouts["skeleton_buttons_layout"])
|
||||
# 2. Assets 面板布局
|
||||
assets_layout = QtWidgets.QVBoxLayout(self.controls["assets_panel"])
|
||||
assets_layout.setContentsMargins(0, 0, 0, 0)
|
||||
assets_layout.setSpacing(5)
|
||||
|
||||
# 控制器组布局
|
||||
self.layouts["controller_group_layout"] = QtWidgets.QVBoxLayout(self.controls["controller_group"])
|
||||
self.layouts["controller_group_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["controller_group_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)
|
||||
|
||||
# 控制器列表
|
||||
self.layouts["controller_group_layout"].addWidget(self.controls["controller_list"])
|
||||
# 添加项目路径标签和输入框
|
||||
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)
|
||||
|
||||
# 控制器操作按钮行
|
||||
self.layouts["controller_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["controller_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["controller_buttons_layout"].setSpacing(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)
|
||||
|
||||
self.layouts["controller_buttons_layout"].addWidget(self.buttons["add_controller"])
|
||||
self.layouts["controller_buttons_layout"].addWidget(self.buttons["remove_controller"])
|
||||
self.layouts["controller_buttons_layout"].addWidget(self.buttons["duplicate_controller"])
|
||||
# 添加Assets组到Assets面板
|
||||
assets_layout.addWidget(self.controls["assets_group"])
|
||||
|
||||
self.layouts["controller_group_layout"].addLayout(self.layouts["controller_buttons_layout"])
|
||||
# 3. Descriptor 面板布局
|
||||
descriptor_layout = QtWidgets.QVBoxLayout(self.controls["descriptor_panel"])
|
||||
descriptor_layout.setContentsMargins(0, 0, 0, 0)
|
||||
descriptor_layout.setSpacing(5)
|
||||
|
||||
# 添加组到左侧面板
|
||||
self.layouts["left_layout"].addWidget(self.controls["skeleton_group"])
|
||||
self.layouts["left_layout"].addWidget(self.controls["controller_group"])
|
||||
# Descriptor 组布局
|
||||
descriptor_group_layout = QtWidgets.QGridLayout(self.controls["descriptor_group"])
|
||||
descriptor_group_layout.setContentsMargins(5, 5, 5, 5)
|
||||
descriptor_group_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)
|
||||
# 添加名称标签和输入框
|
||||
descriptor_group_layout.addWidget(self.controls["name_label"], 0, 0)
|
||||
descriptor_group_layout.addWidget(self.controls["name_input"], 0, 1, 1, 3)
|
||||
|
||||
# 关节属性组布局
|
||||
self.layouts["joint_properties_layout"] = QtWidgets.QVBoxLayout(self.controls["joint_properties_group"])
|
||||
self.layouts["joint_properties_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["joint_properties_layout"].setSpacing(5)
|
||||
# 添加原型标签和下拉框
|
||||
descriptor_group_layout.addWidget(self.controls["archetype_label"], 1, 0)
|
||||
descriptor_group_layout.addWidget(self.controls["archetype_combo"], 1, 1)
|
||||
|
||||
# 关节名称行
|
||||
self.layouts["joint_name_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["joint_name_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["joint_name_layout"].setSpacing(5)
|
||||
# 添加性别标签和下拉框
|
||||
descriptor_group_layout.addWidget(self.controls["gender_label"], 1, 2)
|
||||
descriptor_group_layout.addWidget(self.controls["gender_combo"], 1, 3)
|
||||
|
||||
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_label"])
|
||||
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_input"])
|
||||
# 添加年龄标签和输入框
|
||||
descriptor_group_layout.addWidget(self.controls["age_label"], 2, 0)
|
||||
descriptor_group_layout.addWidget(self.controls["age_spinner"], 2, 1)
|
||||
|
||||
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_name_layout"])
|
||||
# 添加平移单位标签和下拉框
|
||||
descriptor_group_layout.addWidget(self.controls["translation_unit_label"], 3, 0)
|
||||
descriptor_group_layout.addWidget(self.controls["translation_unit_combo"], 3, 1)
|
||||
|
||||
# 关节位置行
|
||||
self.layouts["joint_position_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["joint_position_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["joint_position_layout"].setSpacing(2)
|
||||
# 添加旋转单位标签和下拉框
|
||||
descriptor_group_layout.addWidget(self.controls["rotation_unit_label"], 3, 2)
|
||||
descriptor_group_layout.addWidget(self.controls["rotation_unit_combo"], 3, 3)
|
||||
|
||||
self.layouts["joint_position_layout"].addWidget(self.controls["joint_position_label"])
|
||||
# 添加坐标系统标签和下拉框
|
||||
descriptor_group_layout.addWidget(self.controls["coordinate_system_label"], 4, 0)
|
||||
descriptor_group_layout.addWidget(self.controls["coordinate_system_combo"], 4, 1)
|
||||
|
||||
# 位置坐标行
|
||||
self.layouts["position_coords_layout"] = QtWidgets.QGridLayout()
|
||||
self.layouts["position_coords_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["position_coords_layout"].setSpacing(5)
|
||||
# 添加LOD数量标签和输入框
|
||||
descriptor_group_layout.addWidget(self.controls["lod_count_label"], 4, 2)
|
||||
descriptor_group_layout.addWidget(self.controls["lod_count_spinner"], 4, 3)
|
||||
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_label"], 0, 0)
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_input"], 0, 1)
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_label"], 1, 0)
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_input"], 1, 1)
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_label"], 2, 0)
|
||||
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_input"], 2, 1)
|
||||
# 添加Descriptor组到Descriptor面板
|
||||
descriptor_layout.addWidget(self.controls["descriptor_group"])
|
||||
|
||||
self.layouts["joint_position_layout"].addLayout(self.layouts["position_coords_layout"])
|
||||
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_position_layout"])
|
||||
# 添加各个面板到主分割器
|
||||
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"])
|
||||
|
||||
# 关节旋转行
|
||||
self.layouts["joint_rotation_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["joint_rotation_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["joint_rotation_layout"].setSpacing(2)
|
||||
# 底部按钮区域布局
|
||||
bottom_buttons_layout = QtWidgets.QHBoxLayout(self.controls["bottom_buttons_panel"])
|
||||
bottom_buttons_layout.setContentsMargins(5, 5, 5, 5)
|
||||
bottom_buttons_layout.setSpacing(10)
|
||||
|
||||
self.layouts["joint_rotation_layout"].addWidget(self.controls["joint_rotation_label"])
|
||||
# 添加底部按钮
|
||||
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"])
|
||||
|
||||
# 旋转坐标行
|
||||
self.layouts["rotation_coords_layout"] = QtWidgets.QGridLayout()
|
||||
self.layouts["rotation_coords_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["rotation_coords_layout"].setSpacing(5)
|
||||
# 添加底部按钮区域到主布局
|
||||
main_layout.addWidget(self.controls["bottom_buttons_panel"])
|
||||
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_label"], 0, 0)
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_input"], 0, 1)
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_label"], 1, 0)
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_input"], 1, 1)
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_label"], 2, 0)
|
||||
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_input"], 2, 1)
|
||||
# 设置分割器初始大小
|
||||
self.splitters["main_splitter"].setSizes([400, 100, 200])
|
||||
|
||||
self.layouts["joint_rotation_layout"].addLayout(self.layouts["rotation_coords_layout"])
|
||||
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_rotation_layout"])
|
||||
|
||||
# 关节缩放行
|
||||
self.layouts["joint_scale_layout"] = QtWidgets.QVBoxLayout()
|
||||
self.layouts["joint_scale_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["joint_scale_layout"].setSpacing(2)
|
||||
|
||||
self.layouts["joint_scale_layout"].addWidget(self.controls["joint_scale_label"])
|
||||
|
||||
# 缩放坐标行
|
||||
self.layouts["scale_coords_layout"] = QtWidgets.QGridLayout()
|
||||
self.layouts["scale_coords_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["scale_coords_layout"].setSpacing(5)
|
||||
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_label"], 0, 0)
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_input"], 0, 1)
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_label"], 1, 0)
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_input"], 1, 1)
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_label"], 2, 0)
|
||||
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_input"], 2, 1)
|
||||
|
||||
self.layouts["joint_scale_layout"].addLayout(self.layouts["scale_coords_layout"])
|
||||
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_scale_layout"])
|
||||
|
||||
# 属性按钮行
|
||||
self.layouts["properties_buttons_layout"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["properties_buttons_layout"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["properties_buttons_layout"].setSpacing(5)
|
||||
|
||||
self.layouts["properties_buttons_layout"].addWidget(self.buttons["apply_joint_properties"])
|
||||
self.layouts["properties_buttons_layout"].addWidget(self.buttons["reset_joint_properties"])
|
||||
|
||||
self.layouts["joint_properties_layout"].addLayout(self.layouts["properties_buttons_layout"])
|
||||
|
||||
# 绑定工具组布局
|
||||
self.layouts["binding_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["binding_tools_group"])
|
||||
self.layouts["binding_tools_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["binding_tools_layout"].setSpacing(5)
|
||||
|
||||
# 绑定工具按钮网格
|
||||
self.layouts["binding_tools_grid"] = QtWidgets.QGridLayout()
|
||||
self.layouts["binding_tools_grid"].setContentsMargins(0, 0, 0, 0)
|
||||
self.layouts["binding_tools_grid"].setSpacing(5)
|
||||
|
||||
self.layouts["binding_tools_grid"].addWidget(self.buttons["create_binding"], 0, 0)
|
||||
self.layouts["binding_tools_grid"].addWidget(self.buttons["copy_skin"], 0, 1)
|
||||
self.layouts["binding_tools_grid"].addWidget(self.buttons["mirror_skin"], 1, 0)
|
||||
self.layouts["binding_tools_grid"].addWidget(self.buttons["paint_weights"], 1, 1)
|
||||
|
||||
self.layouts["binding_tools_layout"].addLayout(self.layouts["binding_tools_grid"])
|
||||
|
||||
# 添加组到右侧面板
|
||||
self.layouts["right_layout"].addWidget(self.controls["joint_properties_group"])
|
||||
self.layouts["right_layout"].addWidget(self.controls["binding_tools_group"])
|
||||
|
||||
# 底部工具面板
|
||||
self.layouts["bottom_panel"] = QtWidgets.QHBoxLayout()
|
||||
self.layouts["bottom_panel"].setContentsMargins(2, 2, 2, 2)
|
||||
self.layouts["bottom_panel"].setSpacing(5)
|
||||
|
||||
# DNA组布局
|
||||
self.layouts["dna_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_group"])
|
||||
self.layouts["dna_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["dna_layout"].setSpacing(5)
|
||||
|
||||
self.layouts["dna_layout"].addWidget(self.buttons["import_dna"])
|
||||
self.layouts["dna_layout"].addWidget(self.buttons["export_dna"])
|
||||
self.layouts["dna_layout"].addWidget(self.buttons["calibrate_dna"])
|
||||
|
||||
# 骨骼工具组布局
|
||||
self.layouts["skeleton_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_tools_group"])
|
||||
self.layouts["skeleton_tools_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["skeleton_tools_layout"].setSpacing(5)
|
||||
|
||||
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["import_skeleton"])
|
||||
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["export_skeleton"])
|
||||
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["calibrate_skeleton"])
|
||||
|
||||
# 绑定工具组布局
|
||||
self.layouts["rigging_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["rigging_tools_group"])
|
||||
self.layouts["rigging_tools_layout"].setContentsMargins(5, 10, 5, 5)
|
||||
self.layouts["rigging_tools_layout"].setSpacing(5)
|
||||
|
||||
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_controllers"])
|
||||
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_body"])
|
||||
self.layouts["rigging_tools_layout"].addWidget(self.buttons["clean_rigging"])
|
||||
|
||||
# 添加组到底部面板
|
||||
self.layouts["bottom_panel"].addWidget(self.controls["dna_group"])
|
||||
self.layouts["bottom_panel"].addWidget(self.controls["skeleton_tools_group"])
|
||||
self.layouts["bottom_panel"].addWidget(self.controls["rigging_tools_group"])
|
||||
|
||||
# 添加底部面板到主布局
|
||||
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
|
||||
|
||||
# 将左右面板添加到主分割器
|
||||
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
|
||||
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
|
||||
|
||||
# 设置分割器初始大小和伸缩因子
|
||||
self.splitters["main_splitter"].setSizes([500, 500])
|
||||
|
||||
# 设置分割器的伸缩因子,确保左右栏能够自动调整宽度
|
||||
# 设置分割器的伸缩因子
|
||||
for i in range(self.splitters["main_splitter"].count()):
|
||||
self.splitters["main_splitter"].setStretchFactor(i, 1)
|
||||
|
||||
#======================================= CONNECTION =====================================
|
||||
def create_connections(self):
|
||||
"""
|
||||
创建绑定系统UI信号和槽连接
|
||||
将按钮点击等事件与相应的处理函数连接
|
||||
"""
|
||||
# 左侧面板 - 骨骼列表操作
|
||||
self.buttons["add_joint"].clicked.connect(self.add_joint)
|
||||
self.buttons["remove_joint"].clicked.connect(self.remove_joint)
|
||||
self.buttons["duplicate_joint"].clicked.connect(self.duplicate_joint)
|
||||
self.controls["skeleton_list"].itemSelectionChanged.connect(self.on_joint_selection_changed)
|
||||
|
||||
# 左侧面板 - 控制器列表操作
|
||||
self.buttons["add_controller"].clicked.connect(self.add_controller)
|
||||
self.buttons["remove_controller"].clicked.connect(self.remove_controller)
|
||||
self.buttons["duplicate_controller"].clicked.connect(self.duplicate_controller)
|
||||
self.controls["controller_list"].itemSelectionChanged.connect(self.on_controller_selection_changed)
|
||||
|
||||
# 右侧面板 - 关节属性
|
||||
self.buttons["apply_joint_properties"].clicked.connect(self.apply_joint_properties)
|
||||
self.buttons["reset_joint_properties"].clicked.connect(self.reset_joint_properties)
|
||||
|
||||
# 坐标输入框修改事件
|
||||
self.controls["joint_name_input"].textChanged.connect(self.on_joint_name_changed)
|
||||
self.controls["joint_x_input"].textChanged.connect(lambda: self.on_joint_position_changed("x"))
|
||||
self.controls["joint_y_input"].textChanged.connect(lambda: self.on_joint_position_changed("y"))
|
||||
self.controls["joint_z_input"].textChanged.connect(lambda: self.on_joint_position_changed("z"))
|
||||
self.controls["joint_rx_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("x"))
|
||||
self.controls["joint_ry_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("y"))
|
||||
self.controls["joint_rz_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("z"))
|
||||
self.controls["joint_sx_input"].textChanged.connect(lambda: self.on_joint_scale_changed("x"))
|
||||
self.controls["joint_sy_input"].textChanged.connect(lambda: self.on_joint_scale_changed("y"))
|
||||
self.controls["joint_sz_input"].textChanged.connect(lambda: self.on_joint_scale_changed("z"))
|
||||
|
||||
# 右侧面板 - 绑定工具
|
||||
self.buttons["create_binding"].clicked.connect(self.create_binding)
|
||||
self.buttons["copy_skin"].clicked.connect(self.copy_skin)
|
||||
self.buttons["mirror_skin"].clicked.connect(self.mirror_skin)
|
||||
self.buttons["paint_weights"].clicked.connect(self.paint_weights)
|
||||
|
||||
# 底部工具面板 - DNA操作
|
||||
self.buttons["import_dna"].clicked.connect(self.import_dna)
|
||||
self.buttons["export_dna"].clicked.connect(self.export_dna)
|
||||
self.buttons["calibrate_dna"].clicked.connect(self.calibrate_dna)
|
||||
|
||||
# 底部工具面板 - 骨骼工具
|
||||
self.buttons["import_skeleton"].clicked.connect(self.import_skeleton)
|
||||
self.buttons["export_skeleton"].clicked.connect(self.export_skeleton)
|
||||
self.buttons["calibrate_skeleton"].clicked.connect(self.calibrate_skeleton)
|
||||
|
||||
# 底部工具面板 - 绑定工具
|
||||
self.buttons["generate_controllers"].clicked.connect(self.generate_controllers)
|
||||
self.buttons["generate_body"].clicked.connect(self.generate_body)
|
||||
self.buttons["clean_rigging"].clicked.connect(self.clean_rigging)
|
||||
|
||||
# 分割器移动事件
|
||||
self.splitters["main_splitter"].splitterMoved.connect(self.on_splitter_moved)
|
||||
|
||||
# 添加显示事件处理
|
||||
self.showEvent = self.on_show_event
|
||||
self.splitters["main_splitter"].setStretchFactor(i, 1)
|
@@ -48,11 +48,17 @@ LANG = localization.LANG
|
||||
# 定义窗口大小变化事件处理类
|
||||
# 用于监听窗口大小变化并调整分割器宽度
|
||||
class SplitterResizeHandler(QtCore.QObject):
|
||||
def __init__(self, parent_tab, main_splitter, is_horizontal=True):
|
||||
def __init__(self, parent_tab, main_splitter, is_horizontal=True, panel_count=2, panel_ratio=None):
|
||||
super(SplitterResizeHandler, self).__init__(parent_tab)
|
||||
self.parent_tab = parent_tab
|
||||
self.main_splitter = main_splitter
|
||||
self.is_horizontal = is_horizontal # 是否为水平分割器
|
||||
self.panel_count = panel_count # 面板数量,默认为2(左右面板)
|
||||
|
||||
# 面板比例,默认为None,则使用默认比例
|
||||
# 如果是2面板,默认比例为[1, 1](左右均等)
|
||||
# 如果是3面板,默认比例为[4, 1, 2](Presets面板较大,Assets面板较小,Descriptor面板中等)
|
||||
self.panel_ratio = panel_ratio if panel_ratio else ([1, 1] if panel_count == 2 else [4, 1, 2])
|
||||
|
||||
# 安装事件过滤器到父标签页
|
||||
self.parent_tab.installEventFilter(self)
|
||||
@@ -67,37 +73,227 @@ class SplitterResizeHandler(QtCore.QObject):
|
||||
def adjustSplitterSizes(self):
|
||||
# 确保分割器存在且父标签页可见
|
||||
if self.main_splitter and self.parent_tab.isVisible():
|
||||
# 计算比例总和
|
||||
ratio_sum = sum(self.panel_ratio)
|
||||
|
||||
if self.is_horizontal:
|
||||
# 获取父标签页当前宽度
|
||||
width = self.parent_tab.width()
|
||||
# 设置分割器左右宽度均等
|
||||
self.main_splitter.setSizes([width // 2, width // 2])
|
||||
print(f"分割器 - 窗口大小变化,调整水平分割器宽度为: {width // 2}, {width // 2}")
|
||||
# 根据面板数量设置分割器大小
|
||||
if self.panel_count == 2:
|
||||
# 设置分割器左右宽度按比例分配
|
||||
sizes = [int(width * ratio / ratio_sum) for ratio in self.panel_ratio]
|
||||
self.main_splitter.setSizes(sizes)
|
||||
print(f"分割器 - 窗口大小变化,调整水平分割器宽度为: {sizes}")
|
||||
elif self.panel_count == 3:
|
||||
# 设置三面板分割器宽度按比例分配
|
||||
sizes = [int(width * ratio / ratio_sum) for ratio in self.panel_ratio]
|
||||
self.main_splitter.setSizes(sizes)
|
||||
print(f"分割器 - 窗口大小变化,调整三面板水平分割器宽度为: {sizes}")
|
||||
else:
|
||||
# 获取父标签页当前高度
|
||||
height = self.parent_tab.height()
|
||||
# 设置分割器上下比例为3:1
|
||||
self.main_splitter.setSizes([height * 3 // 4, height // 4])
|
||||
print(f"分割器 - 窗口大小变化,调整垂直分割器高度为: {height * 3 // 4}, {height // 4}")
|
||||
# 根据面板数量设置分割器大小
|
||||
if self.panel_count == 2:
|
||||
# 设置分割器上下高度按比例分配
|
||||
sizes = [int(height * ratio / ratio_sum) for ratio in self.panel_ratio]
|
||||
self.main_splitter.setSizes(sizes)
|
||||
print(f"分割器 - 窗口大小变化,调整垂直分割器高度为: {sizes}")
|
||||
elif self.panel_count == 3:
|
||||
# 设置三面板分割器高度按比例分配
|
||||
sizes = [int(height * ratio / ratio_sum) for ratio in self.panel_ratio]
|
||||
self.main_splitter.setSizes(sizes)
|
||||
print(f"分割器 - 窗口大小变化,调整三面板垂直分割器高度为: {sizes}")
|
||||
|
||||
# 使用类来管理UI控件,避免全局变量
|
||||
class BaseUI:
|
||||
class BaseUI(object):
|
||||
"""
|
||||
基础UI类 - 管理所有UI控件
|
||||
使用字典存储控件、按钮、布局和分割器引用,避免全局变量
|
||||
UI基类
|
||||
所有UI面板的基类,提供通用的UI功能
|
||||
"""
|
||||
def __init__(self):
|
||||
# UI控件字典
|
||||
"""
|
||||
初始化UI基类
|
||||
"""
|
||||
# 初始化字典
|
||||
self.controls = {}
|
||||
# 按钮字典
|
||||
self.buttons = {}
|
||||
# 布局字典
|
||||
self.layouts = {}
|
||||
# 分割器字典
|
||||
self.buttons = {}
|
||||
self.splitters = {}
|
||||
# 分割器大小处理器字典
|
||||
self.resize_handlers = {}
|
||||
self.inputs = {}
|
||||
self.labels = {}
|
||||
|
||||
# 创建主控件
|
||||
self.main_widget = None
|
||||
|
||||
def on_show_event(self, event):
|
||||
"""
|
||||
显示事件处理
|
||||
当面板显示时重置分割器大小
|
||||
|
||||
Args:
|
||||
event: 显示事件对象
|
||||
"""
|
||||
# 重置分割器大小
|
||||
self.reset_splitter_sizes()
|
||||
|
||||
# 调用父类的showEvent方法
|
||||
super(BaseUI, self).showEvent(event)
|
||||
|
||||
def reset_splitter_sizes(self):
|
||||
"""
|
||||
重置分割器大小,设置三个面板的初始大小
|
||||
Presets面板较大,显示预设图片;Assets面板较小;Descriptor面板中等
|
||||
"""
|
||||
if hasattr(self, 'splitters') and 'main_splitter' in self.splitters and self.splitters["main_splitter"]:
|
||||
# 尝试从设置中读取分割器大小
|
||||
preset_size = cmds.optionVar(query="MetaFusionRiggingPresetsPanelSize") if cmds.optionVar(exists="MetaFusionRiggingPresetsPanelSize") else 400
|
||||
assets_size = cmds.optionVar(query="MetaFusionRiggingAssetsPanelSize") if cmds.optionVar(exists="MetaFusionRiggingAssetsPanelSize") else 100
|
||||
descriptor_size = cmds.optionVar(query="MetaFusionRiggingDescriptorPanelSize") if cmds.optionVar(exists="MetaFusionRiggingDescriptorPanelSize") else 200
|
||||
|
||||
# 设置分割器大小
|
||||
self.splitters["main_splitter"].setSizes([preset_size, assets_size, descriptor_size])
|
||||
|
||||
def create_widgets(self):
|
||||
"""
|
||||
创建UI控件
|
||||
创建所有UI控件并存储到字典中
|
||||
"""
|
||||
# 子类实现
|
||||
pass
|
||||
|
||||
def create_layouts(self):
|
||||
"""
|
||||
创建UI布局
|
||||
创建所有UI布局并存储到字典中
|
||||
"""
|
||||
# 子类实现
|
||||
pass
|
||||
|
||||
def connect_ui_signals(self):
|
||||
"""
|
||||
连接UI信号和槽
|
||||
设置UI控件的事件处理函数
|
||||
"""
|
||||
# 子类实现
|
||||
pass
|
||||
|
||||
def showEvent(self, event):
|
||||
"""
|
||||
显示事件
|
||||
当面板显示时调用on_show_event方法
|
||||
|
||||
Args:
|
||||
event: 显示事件对象
|
||||
"""
|
||||
# 调用自定义的显示事件处理方法
|
||||
self.on_show_event(event)
|
||||
|
||||
# 分割器相关的工具函数
|
||||
def update_splitter_position(splitter, sizes=None):
|
||||
"""
|
||||
更新分割器位置
|
||||
|
||||
Args:
|
||||
splitter: 分割器对象
|
||||
sizes: 分割器大小列表,如果为None则使用当前分割器大小
|
||||
"""
|
||||
if not splitter:
|
||||
return
|
||||
|
||||
# 记录当前分割器位置
|
||||
if sizes is None:
|
||||
sizes = splitter.sizes()
|
||||
|
||||
# 将分割器位置保存到设置中
|
||||
# 如果是三面板分割器,则保存三个大小值
|
||||
if len(sizes) == 3:
|
||||
# 保存三面板分割器位置(Presets、Assets、Descriptor)
|
||||
cmds.optionVar(intValue=["MetaFusionRiggingPresetsPanelSize", sizes[0]])
|
||||
cmds.optionVar(intValue=["MetaFusionRiggingAssetsPanelSize", sizes[1]])
|
||||
cmds.optionVar(intValue=["MetaFusionRiggingDescriptorPanelSize", sizes[2]])
|
||||
else:
|
||||
# 保存左右分割器位置
|
||||
cmds.optionVar(intValue=["MetaFusionRiggingLeftPanelSize", sizes[0]])
|
||||
cmds.optionVar(intValue=["MetaFusionRiggingRightPanelSize", sizes[1]])
|
||||
print(f"Splitter sizes updated: {sizes}")
|
||||
|
||||
# 通用UI事件处理函数
|
||||
def on_splitter_moved(ui_instance, pos, index):
|
||||
"""
|
||||
分割器移动事件处理
|
||||
记录当前分割器位置
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例,包含splitters字典
|
||||
pos: 分割器位置
|
||||
index: 分割器索引
|
||||
"""
|
||||
if hasattr(ui_instance, 'splitters') and 'main_splitter' in ui_instance.splitters:
|
||||
update_splitter_position(ui_instance.splitters["main_splitter"])
|
||||
|
||||
def connect_ui_signals(ui_instance, signal_mapping):
|
||||
"""
|
||||
连接UI信号和槽
|
||||
设置UI控件的事件处理函数
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例,包含控件和布局
|
||||
signal_mapping: 信号映射字典,格式为:
|
||||
{
|
||||
'widget_type': { # 'buttons', 'inputs', 'splitters'等
|
||||
'widget_name': { # 控件名称
|
||||
'signal': 'signal_name', # 信号名称,如'clicked', 'valueChanged'等
|
||||
'handler': handler_function, # 处理函数
|
||||
'args': [arg1, arg2, ...] # 可选,处理函数的参数
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
# 遍历信号映射字典
|
||||
for widget_type, widgets in signal_mapping.items():
|
||||
# 获取控件字典
|
||||
widget_dict = getattr(ui_instance, widget_type, {})
|
||||
|
||||
# 遍历控件
|
||||
for widget_name, signal_info in widgets.items():
|
||||
# 检查控件是否存在
|
||||
if widget_name in widget_dict:
|
||||
widget = widget_dict[widget_name]
|
||||
signal_name = signal_info.get('signal')
|
||||
handler = signal_info.get('handler')
|
||||
args = signal_info.get('args', [])
|
||||
|
||||
# 获取信号对象
|
||||
signal = getattr(widget, signal_name, None)
|
||||
|
||||
# 连接信号和槽
|
||||
if signal and handler:
|
||||
if args:
|
||||
signal.connect(lambda *extra, h=handler, a=args: h(*a))
|
||||
else:
|
||||
signal.connect(handler)
|
||||
|
||||
def connect_maya_selection_changed(ui_instance, handler, parent_widget=None):
|
||||
"""
|
||||
连接Maya选择变化事件
|
||||
|
||||
Args:
|
||||
ui_instance: UI实例
|
||||
handler: 选择变化事件处理函数
|
||||
parent_widget: 父控件,用于设置scriptJob的parent参数
|
||||
"""
|
||||
# 如果没有指定父控件,则使用UI实例的main_widget
|
||||
if parent_widget is None and hasattr(ui_instance, 'main_widget'):
|
||||
parent_widget = ui_instance.main_widget
|
||||
|
||||
# 创建scriptJob
|
||||
if parent_widget:
|
||||
job_id = cmds.scriptJob(event=["SelectionChanged", handler], parent=parent_widget.objectName())
|
||||
return job_id
|
||||
return None
|
||||
|
||||
# 获取Maya主窗口
|
||||
def get_maya_main_window():
|
||||
"""
|
||||
获取Maya主窗口
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user