MetaFusion/scripts/ui/widgets.py

224 lines
7.4 KiB
Python
Raw Normal View History

2025-02-09 21:35:41 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
2025-02-09 22:11:50 +08:00
#===================================== 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
2025-02-11 00:04:32 +08:00
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}")
2025-02-09 23:22:48 +08:00
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)