#!/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 ToolShelf(QtWidgets.QToolBar): def __init__(self, parent=None): super(ToolShelf, self).__init__(parent) self.setIconSize(QtCore.QSize(24, 24)) self.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) # 添加工具按钮 self._add_tools() def _add_tools(self): """添加工具按钮""" tools = [ ("保存 DNA", "save.png"), ("加载当前项目 DNA", "open.png"), None, # 分隔符 ("创建RL4节点", "connect.png"), ("删除RL4节点", "disconnect.png"), None, ("导出蒙皮", "export_skin.png"), ("导入蒙皮", "import_skin.png"), ("复制蒙皮", "copy_skin.png"), None, ("帮助文档", "help.png"), ("关于", "about.png") ] for tool in tools: if tool is None: self.addSeparator() else: name, icon = tool action = QtWidgets.QAction(QtGui.QIcon(f"{config.ICONS_PATH}/{icon}"), name, self) self.addAction(action) class IconButton(QtWidgets.QPushButton): """带图标的按钮""" def __init__(self, icon_name, tooltip="", size=24, parent=None): super(IconButton, self).__init__(parent) self._setup_ui(icon_name, tooltip, size) def _setup_ui(self, icon_name, tooltip, size): # 设置图标 icon = QtGui.QIcon(f"{config.ICONS_PATH}/{icon_name}") self.setIcon(icon) self.setIconSize(QtCore.QSize(size, size)) # 设置样式 self.setFixedSize(size, size) self.setToolTip(tooltip) self.setStyleSheet(""" QPushButton { border: none; background: transparent; } QPushButton:hover { background: rgba(255, 255, 255, 0.1); } QPushButton:pressed { background: rgba(255, 255, 255, 0.2); } """) class SearchLineEdit(QtWidgets.QLineEdit): """带搜索图标的输入框""" def __init__(self, parent=None): super(SearchLineEdit, self).__init__(parent) self._setup_ui() def _setup_ui(self): # 设置样式 self.setPlaceholderText("搜索...") # 添加搜索图标 search_action = QtWidgets.QAction(self) search_action.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/search.png")) self.addAction(search_action, QtWidgets.QLineEdit.LeadingPosition) # 添加清除按钮 self.setClearButtonEnabled(True) class CollapsibleWidget(QtWidgets.QWidget): """可折叠的控件组""" def __init__(self, title="", parent=None): super(CollapsibleWidget, self).__init__(parent) self._setup_ui(title) self._create_connections() def _setup_ui(self, title): # === Main Layout === self.main_layout = QtWidgets.QVBoxLayout(self) self.main_layout.setContentsMargins(0, 0, 0, 0) self.main_layout.setSpacing(0) # === Header === self.header_widget = QtWidgets.QWidget() header_layout = QtWidgets.QHBoxLayout(self.header_widget) header_layout.setContentsMargins(5, 5, 5, 5) # 展开/折叠按钮 self.toggle_btn = IconButton("arrow_down.png", size=16) header_layout.addWidget(self.toggle_btn) # 标题 title_label = QtWidgets.QLabel(title) header_layout.addWidget(title_label) header_layout.addStretch() self.main_layout.addWidget(self.header_widget) # === Content === self.content_widget = QtWidgets.QWidget() self.content_layout = QtWidgets.QVBoxLayout(self.content_widget) self.content_layout.setContentsMargins(20, 5, 5, 5) self.main_layout.addWidget(self.content_widget) def _create_connections(self): self.toggle_btn.clicked.connect(self._toggle_content) def _toggle_content(self): """切换内容显示/隐藏""" if self.content_widget.isVisible(): self.content_widget.hide() self.toggle_btn.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/arrow_right.png")) else: self.content_widget.show() self.toggle_btn.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/arrow_down.png")) def add_widget(self, widget): """添加控件到内容区域""" self.content_layout.addWidget(widget) class LabeledSpinBox(QtWidgets.QWidget): """带标签的数值输入框""" valueChanged = QtCore.Signal(float) # 值改变信号 def __init__(self, label="", min_value=0.0, max_value=1.0, decimals=3, parent=None): super(LabeledSpinBox, self).__init__(parent) self._setup_ui(label, min_value, max_value, decimals) self._create_connections() def _setup_ui(self, label, min_value, max_value, decimals): # === Layout === layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # 标签 self.label = QtWidgets.QLabel(label) layout.addWidget(self.label) # 数值输入框 self.spin_box = QtWidgets.QDoubleSpinBox() self.spin_box.setMinimum(min_value) self.spin_box.setMaximum(max_value) self.spin_box.setDecimals(decimals) layout.addWidget(self.spin_box) def _create_connections(self): self.spin_box.valueChanged.connect(self.valueChanged.emit) def value(self): return self.spin_box.value() def setValue(self, value): self.spin_box.setValue(value) class StatusWidget(QtWidgets.QWidget): """状态显示控件""" def __init__(self, parent=None): super(StatusWidget, self).__init__(parent) self._setup_ui() def _setup_ui(self): # === Layout === layout = QtWidgets.QHBoxLayout(self) layout.setContentsMargins(5, 2, 5, 2) # 状态图标 self.icon_label = QtWidgets.QLabel() self.icon_label.setFixedSize(16, 16) layout.addWidget(self.icon_label) # 状态文本 self.text_label = QtWidgets.QLabel() layout.addWidget(self.text_label) layout.addStretch() def set_status(self, status, message): """设置状态 status: 'normal', 'warning', 'error' """ icon_map = { 'normal': 'status_normal.png', 'warning': 'status_warning.png', 'error': 'status_error.png' } if status in icon_map: self.icon_label.setPixmap( QtGui.QPixmap(f"{config.ICONS_PATH}/{icon_map[status]}") ) self.text_label.setText(message)