#!/usr/bin/env python # -*- coding: utf-8 -*- #===================================== 1. Module Imports ===================================== import maya.OpenMayaUI as omui from scripts import config import maya.cmds as cmds import maya.mel as mel import webbrowser import sys import os from .. import config QtCore, QtGui, QtWidgets, wrapInstance = config.Qt() if QtCore is None or QtGui is None or QtWidgets is None or wrapInstance is None: print(f"Qt加载失败: {QtCore}, {QtGui}, {QtWidgets}, {wrapInstance}") class MeshItem(QtWidgets.QWidget): """单个网格项控件""" def __init__(self, mesh_name, parent=None): super(MeshItem, self).__init__(parent) self._setup_ui(mesh_name) self._create_connections() def _setup_ui(self, mesh_name): """设置UI布局""" # === Main Layout === self.main_layout = QtWidgets.QHBoxLayout(self) self.main_layout.setContentsMargins(2, 2, 2, 2) self.main_layout.setSpacing(4) # === Widgets === # 网格名称标签 self.name_label = QtWidgets.QLabel(mesh_name) self.name_label.setMinimumWidth(100) # 网格路径输入框 self.path_edit = QtWidgets.QLineEdit() self.path_edit.setReadOnly(True) # 添加按钮 self.add_btn = QtWidgets.QPushButton("添加...") self.add_btn.setFixedWidth(60) # === Layout === self.main_layout.addWidget(self.name_label) self.main_layout.addWidget(self.path_edit) self.main_layout.addWidget(self.add_btn) # === Style === self._setup_style() def _setup_style(self): """设置样式""" self.setStyleSheet(""" QWidget { background: #2D2D2D; } QLabel { color: #CCCCCC; font-size: 12px; } QLineEdit { background: #3D3D3D; border: 1px solid #555555; border-radius: 2px; padding: 4px 8px; color: #CCCCCC; } QPushButton { background: #3D3D3D; border: 1px solid #555555; border-radius: 2px; padding: 4px 12px; color: #CCCCCC; min-width: 60px; } QPushButton:hover { background: #454545; } QPushButton:pressed { background: #2A2A2A; } """) def _create_connections(self): """创建信号连接""" self.add_btn.clicked.connect(self._on_add_clicked) def _on_add_clicked(self): """添加按钮点击""" # TODO: 实现添加逻辑 pass class MeshesTab(QtWidgets.QWidget): def __init__(self, parent=None): super(MeshesTab, self).__init__(parent) self._setup_ui() self._create_connections() def _setup_ui(self): """设置UI布局""" # === Main Layout === self.main_layout = QtWidgets.QVBoxLayout(self) self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) # === 顶部工具栏 === self.toolbar = QtWidgets.QWidget() toolbar_layout = QtWidgets.QHBoxLayout(self.toolbar) toolbar_layout.setContentsMargins(4, 4, 4, 4) toolbar_layout.setSpacing(4) # Meta-Human下拉框 self.preset_combo = QtWidgets.QComboBox() self.preset_combo.addItem("Meta-Human") self.preset_combo.setFixedWidth(120) # 删除按钮移到LOD页面的功能按钮区域 toolbar_layout.addStretch() # === 中间内容区 === self.content = QtWidgets.QWidget() content_layout = QtWidgets.QVBoxLayout(self.content) content_layout.setContentsMargins(0, 0, 0, 0) content_layout.setSpacing(0) # LOD标签页 self.lod_tabs = QtWidgets.QTabWidget() for i in range(8): tab = self._create_lod_page(i) self.lod_tabs.addTab(tab, f"LOD{i}") content_layout.addWidget(self.lod_tabs) # === 底部工具栏 === self.bottom_toolbar = self._create_bottom_toolbar() # === 添加到主布局 === self.main_layout.addWidget(self.toolbar) self.main_layout.addWidget(self.content) self.main_layout.addWidget(self.bottom_toolbar) # === 设置样式 === self._setup_style() def _create_lod_page(self, lod_index): """创建单个LOD页面""" # === Widget === widget = QtWidgets.QWidget() # === Main Layout === layout = QtWidgets.QVBoxLayout(widget) layout.setContentsMargins(8, 8, 8, 8) layout.setSpacing(12) # 增加间距 # === 网格列表区域 === scroll = QtWidgets.QScrollArea() scroll.setWidgetResizable(True) scroll.setFrameShape(QtWidgets.QFrame.NoFrame) content = QtWidgets.QWidget() content_layout = QtWidgets.QVBoxLayout(content) content_layout.setContentsMargins(0, 0, 0, 0) content_layout.setSpacing(0) # 将项目间距改为0 # 创建网格项 meshes = config.LOD_MESHES[f"LOD{lod_index}"] for mesh in meshes: item = self._create_mesh_item(mesh) content_layout.addWidget(item) content_layout.addStretch() scroll.setWidget(content) # === 底部功能按钮 === buttons = QtWidgets.QWidget() button_layout = QtWidgets.QHBoxLayout(buttons) button_layout.setContentsMargins(0, 8, 0, 8) # 创建功能按钮 load_btn = self._create_tool_button("自动加载模型", "load_meshes.png", "fileOpen.png") standardize_btn = self._create_tool_button("标准化命名", "standardized_naming.png", "setEdNormalize.png") group_btn = self._create_tool_button("自动分组", "automatic_grouping.png", "menuIconEdit.png") delete_btn = self._create_tool_button("清理", "delete.png", "delete.png") # 统一按钮高度 for btn in [load_btn, standardize_btn, group_btn, delete_btn]: btn.setFixedHeight(32) # 设置为与模型分离按钮相同的高度 # 创建按钮容器 button_container = QtWidgets.QWidget() container_layout = QtWidgets.QHBoxLayout(button_container) container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(4) # 减小按钮间距为4 # 添加按钮到容器,使用弹性空间使按钮居中 container_layout.addStretch(1) for btn in [load_btn, standardize_btn, group_btn, delete_btn]: container_layout.addWidget(btn) if btn != delete_btn: # 最后一个按钮后不添加间距 container_layout.addSpacing(4) # 添加固定间距 container_layout.addStretch(1) button_layout.addWidget(button_container) # === 添加到主布局 === layout.addWidget(scroll) layout.addWidget(buttons) # 添加窗口大小变化事件处理 def on_resize(event): width = event.size().width() available_width = width - 28 # 28是左右边距(16)和按钮间距(4*3)的总和 button_width = (available_width) // 4 for btn in [load_btn, standardize_btn, group_btn, delete_btn]: btn.setFixedWidth(button_width) super(type(widget), widget).resizeEvent(event) widget.resizeEvent = on_resize return widget def _create_mesh_item(self, mesh_name): """创建网格项""" item = QtWidgets.QWidget() layout = QtWidgets.QHBoxLayout(item) layout.setContentsMargins(4, 0, 4, 0) # 移除上下边距 layout.setSpacing(4) # 设置item的最小高度,确保内容完整显示 item.setMinimumHeight(40) # 左侧容器(标签和输入框) left_container = QtWidgets.QWidget() left_layout = QtWidgets.QHBoxLayout(left_container) left_layout.setContentsMargins(0, 0, 0, 0) left_layout.setSpacing(1) # 网格名称标签 name_label = QtWidgets.QLabel(mesh_name + ":") # 添加冒号 name_label.setFixedWidth(50) # 减小标签宽度 name_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) name_label.setStyleSheet(""" QLabel { color: #CCCCCC; padding-right: 0px; } """) # 网格路径输入框 path_edit = QtWidgets.QLineEdit() path_edit.setPlaceholderText("输入或选择模型路径...") path_edit.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) path_edit.setFixedHeight(24) path_edit.setStyleSheet(""" QLineEdit { background: #1d1d1d; border: 2px solid #444444; /* 调整边框颜色 */ border-radius: 5px; /* 减小圆角 */ padding: 2px 4px; color: #CCCCCC; } QLineEdit:hover { border: 1px solid #555555; } QLineEdit:focus { border: 1px solid #666666; background: #2A2A2A; } """) left_layout.addWidget(name_label) left_layout.addWidget(path_edit) # 加载按钮 add_btn = QtWidgets.QPushButton("加载...") add_btn.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/target.png")) add_btn.setToolTip("浏览...") add_btn.setFixedSize(100, 24) add_btn.setStyleSheet(""" QPushButton { background: #232323; border: 2px solid #444444; /* 调整边框颜色 */ border-radius: 5px; /* 减小圆角 */ padding: 2px 4px; color: #CCCCCC; text-align: center; /* 居中对齐 */ } QPushButton:hover { background: #454545; border: 1px solid #555555; } QPushButton:pressed { background: #2A2A2A; border: 1px solid #666666; } """) # 添加到主布局 layout.addWidget(left_container, stretch=1) layout.addWidget(add_btn) return item def _create_tool_button(self, text, icon_name, fallback_icon=None): """创建工具按钮""" btn = QtWidgets.QPushButton(text) # 尝试使用自定义图标,如果失败则使用Maya内置图标 icon_path = f"{config.ICONS_PATH}/{icon_name}" print(f"尝试加载图标: {icon_path}") # 添加调试输出 if os.path.exists(icon_path): btn.setIcon(QtGui.QIcon(icon_path)) print(f"成功加载自定义图标: {icon_path}") elif fallback_icon: btn.setIcon(QtGui.QIcon(f":{fallback_icon}")) print(f"使用Maya内置图标: {fallback_icon}") else: print(f"未能找到图标: {icon_path}") btn.setStyleSheet(""" QPushButton { background: #3D3D3D; border: 1px solid #555555; border-radius: 2px; padding: 4px 8px; color: #CCCCCC; text-align: left; icon-size: 16px; min-height: 32px; # 统一按钮高度 } QPushButton:hover { background: #454545; } QPushButton:pressed { background: #2A2A2A; } """) return btn def _create_bottom_toolbar(self): """创建底部工具栏""" # === Widget === widget = QtWidgets.QWidget() widget.setFixedHeight(180) # 增加高度 # === Main Layout === layout = QtWidgets.QVBoxLayout(widget) layout.setContentsMargins(8, 8, 8, 8) # 增加边距 layout.setSpacing(8) # === 第一行工具栏 - 预设和LOD === first_row = QtWidgets.QWidget() first_layout = QtWidgets.QHBoxLayout(first_row) first_layout.setContentsMargins(4, 0, 4, 0) first_layout.setSpacing(4) # 预设名称 self.preset_label = QtWidgets.QLabel("预设名称:") self.preset_name_combo = QtWidgets.QComboBox() self.preset_name_combo.addItem("Meta-Human") self.preset_name_combo.setFixedWidth(150) self.preset_name_combo.setFixedHeight(32) # 设置为与模型分离按钮相同的高度 # 选择LOD self.lod_label = QtWidgets.QLabel("选择LOD:") self.lod_combo = QtWidgets.QComboBox() self.lod_combo.addItems(["全部"] + [f"LOD{i}" for i in range(8)]) self.lod_combo.setFixedWidth(100) self.lod_combo.setFixedHeight(32) # 设置为与模型分离按钮相同的高度 # 创建LOD按钮 self.create_lod_btn = QtWidgets.QPushButton() self.create_lod_btn.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/create_lod.png")) self.create_lod_btn.setText("创建LOD") self.create_lod_btn.setFixedHeight(32) # 设置为与模型分离按钮相同的高度 first_layout.addWidget(self.preset_label) first_layout.addWidget(self.preset_name_combo) first_layout.addStretch() first_layout.addWidget(self.lod_label) first_layout.addWidget(self.lod_combo) first_layout.addWidget(self.create_lod_btn) # === 功能按钮区域 === buttons_widget = QtWidgets.QWidget() buttons_layout = QtWidgets.QVBoxLayout(buttons_widget) buttons_layout.setContentsMargins(4, 4, 4, 4) buttons_layout.setSpacing(8) # 创建按钮行 row1 = QtWidgets.QWidget() row1_layout = QtWidgets.QHBoxLayout(row1) row1_layout.setContentsMargins(0, 0, 0, 0) row1_layout.setSpacing(8) row2 = QtWidgets.QWidget() row2_layout = QtWidgets.QHBoxLayout(row2) row2_layout.setContentsMargins(0, 0, 0, 0) row2_layout.setSpacing(8) row3 = QtWidgets.QWidget() row3_layout = QtWidgets.QHBoxLayout(row3) row3_layout.setContentsMargins(0, 0, 0, 0) row3_layout.setSpacing(8) # 创建按钮 self.separate_btn = self._create_tool_button("模型分离", "separate.png", "polySplitVertex.png") self.face_accessory_btn = self._create_tool_button("生成面部配件", "supplement_meshes.png", "polyCreateFacet.png") self.fix_normal_btn = self._create_tool_button("修复法线", "repair_normals.png", "polyNormal.png") self.fix_vertex_order_btn = self._create_tool_button("修复点序", "repair_vertex_order.png", "polyNormalPerVertex.png") self.fix_seam_btn = self._create_tool_button("修复接缝", "fix_seam.png", "polyChipOff.png") # 设置按钮固定宽度 button_width = (widget.width() - 24) // 2 # 24是左右边距和按钮间距(8)的总和 for btn in [self.separate_btn, self.face_accessory_btn, self.fix_normal_btn, self.fix_vertex_order_btn, self.fix_seam_btn]: btn.setFixedWidth(button_width) # 添加按钮到行 row1_layout.addStretch() row1_layout.addWidget(self.separate_btn) row1_layout.addWidget(self.face_accessory_btn) row1_layout.addStretch() row2_layout.addStretch() row2_layout.addWidget(self.fix_normal_btn) row2_layout.addWidget(self.fix_vertex_order_btn) row2_layout.addStretch() # 修复接缝按钮不居中 row3_layout.addWidget(self.fix_seam_btn) row3_layout.addStretch() # 添加行到布局 buttons_layout.addWidget(row1) buttons_layout.addWidget(row2) buttons_layout.addWidget(row3) # === 添加到主布局 === layout.addWidget(first_row) layout.addWidget(buttons_widget) # 添加窗口大小变化事件处理 widget.resizeEvent = lambda event: self._adjust_button_widths(event, [ self.separate_btn, self.face_accessory_btn, self.fix_normal_btn, self.fix_vertex_order_btn, self.fix_seam_btn ]) return widget def _adjust_button_widths(self, event, buttons): """调整按钮宽度以适应窗口大小""" width = event.size().width() button_width = (width - 24) // 2 # 24是左右边距和按钮间距(8)的总和 for btn in buttons: btn.setFixedWidth(button_width) def _setup_style(self): """设置样式""" # 工具栏样式 self.toolbar.setStyleSheet(""" QWidget { background: #2D2D2D; } QComboBox { background: #3D3D3D; border: 1px solid #555555; border-radius: 2px; padding: 4px; color: #CCCCCC; } """) # 标签页样式 self.lod_tabs.setStyleSheet(""" QTabWidget::pane { border: none; background: #2D2D2D; } QTabBar::tab { background: #3D3D3D; border: none; min-width: 40px; # 减小最小宽度 padding: 4px 8px; # 减小内边距 color: #CCCCCC; margin-right: 1px; } QTabBar::tab:selected { background: #4D4D4D; color: #FFFFFF; } QTabBar::tab:hover:!selected { background: #454545; } QTabBar::tab:first { margin-left: 0px; } """) # 应用样式到下拉框 for combo in [self.preset_combo, self.preset_name_combo, self.lod_combo]: combo.setStyleSheet(""" QComboBox { background: #3D3D3D; border: 1px solid #555555; border-radius: 2px; padding: 4px; color: #CCCCCC; } """) # 应用样式到标签 for label in [self.preset_label, self.lod_label]: label.setStyleSheet("color: #CCCCCC;") def _create_connections(self): """创建信号连接""" # 顶部工具栏 self.preset_combo.currentIndexChanged.connect(self._on_preset_changed) # 底部工具栏 self.create_lod_btn.clicked.connect(self._on_create_lod) self.separate_btn.clicked.connect(self._on_separate) self.face_accessory_btn.clicked.connect(self._on_face_accessory) self.fix_normal_btn.clicked.connect(self._on_fix_normal) self.fix_vertex_order_btn.clicked.connect(self._on_fix_vertex_order) self.fix_seam_btn.clicked.connect(self._on_fix_seam) # === Event Handlers === def _on_preset_changed(self, index): """预设改变""" # TODO: 实现预设切换 pass def _on_create_lod(self): """生成当前LOD""" # TODO: 实现生成当前LOD pass def _on_separate(self): """模型分离""" # TODO: 实现模型分离 pass def _on_face_accessory(self): """生成面部配件""" # TODO: 实现生成面部配件 pass def _on_fix_normal(self): """修复法线""" # TODO: 实现修复法线 pass def _on_fix_vertex_order(self): """修复点序""" # TODO: 实现修复点序 pass def _on_fix_seam(self): """修复接缝""" # TODO: 实现修复接缝 pass def _on_load_meshes(self, lod_index): """自动加载模型""" # TODO: 实现自动加载模型 print(f"加载 LOD{lod_index} 的模型") pass def _on_standardize_names(self, lod_index): """标准化命名""" # TODO: 实现标准化命名 print(f"标准化 LOD{lod_index} 的命名") pass def _on_auto_group(self, lod_index): """自动分组""" # TODO: 实现自动分组 print(f"自动分组 LOD{lod_index}") pass if __name__ == "__main__": pass