MetaCore-startup/MetaCore/ui/widget.py
2025-10-17 16:56:28 +08:00

411 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import re
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QLabel,
QTreeView, QTreeWidget, QTreeWidgetItem, QWidget,
QFileDialog, QMessageBox, QAbstractItemView, QMenu, QDockWidget, QButtonGroup, QToolButton, QFrame, QSizePolicy)
from PyQt5.QtCore import Qt, QUrl, QMimeData, QPoint, QSize
from PyQt5.QtGui import QDrag, QPainter, QPixmap, QPen, QBrush, QFont
from PyQt5.sip import wrapinstance
from ui.icon_manager import IconManager
class UniversalMessageDialog(QDialog):
"""通用消息对话框类 - 支持不同图标和按钮配置"""
# 消息类型枚举
SUCCESS = "success_icon"
WARNING = "warning_icon"
ERROR = "fail_icon"
INFO = "info"
def __init__(self, parent, title, message, message_type=INFO, show_cancel=True,
confirm_text="确认", cancel_text="取消", icon_size=QSize(20, 20)):
"""
初始化通用消息对话框
Args:
parent: 父窗口
title: 对话框标题
message: 消息内容
message_type: 消息类型 (SUCCESS, WARNING, ERROR, INFO)
show_cancel: 是否显示取消按钮
confirm_text: 确认按钮文字
cancel_text: 取消按钮文字
icon_size: 图标尺寸
"""
super().__init__(parent)
self.setWindowTitle(title)
self.setObjectName("universalMessageDialog")
self.setModal(True)
self.resize(508, 134)
self.setMinimumSize(508, 134)
self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground, True)
# 对话框配置
self.message_type = message_type
self.show_cancel = show_cancel
self.confirm_text = confirm_text
self.cancel_text = cancel_text
self.icon_size = icon_size
# 拖拽相关
self.dragging = False
self.drag_position = QPoint()
# 图标管理
self.icon_manager = IconManager()
self._title_icon_size = QSize(18, 18)
self._icon_close = self.icon_manager.get_icon('close_bt_icon', self._title_icon_size)
# 根据消息类型获取对应图标
self._message_icon = self._get_message_icon()
# 设置样式
self._setup_styles()
# 创建UI
self._create_ui(message)
def _get_message_icon(self):
"""根据消息类型获取对应图标"""
icon_map = {
self.SUCCESS: 'success_icon',
self.WARNING: 'warning_icon',
self.ERROR: 'fail_icon',
self.INFO: 'success_icon' # 默认使用成功图标
}
icon_name = icon_map.get(self.message_type, 'success_icon')
return self.icon_manager.get_icon(icon_name, self.icon_size)
def _setup_styles(self):
"""设置对话框样式"""
self.setStyleSheet("""
QDialog#universalMessageDialog {
background-color: transparent;
border: none;
}
QFrame#baseFrame {
background-color: #19191B;
border: 1px solid #3E3E42;
border-radius: 5px;
}
QWidget#titleBar {
background-color: transparent;
border: none;
border-radius: 5px 5px 0px 0px;
min-height: 32px;
max-height: 32px;
}
QWidget#titleBar QWidget {
background-color: transparent;
border: none;
}
QLabel#titleLabel {
color: #FFFFFF;
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.7px;
}
QWidget#controlButtons QPushButton {
background-color: transparent;
border: none;
color: #EBEBEB;
font-size: 14px;
min-width: 18px;
max-width: 18px;
min-height: 18px;
max-height: 18px;
padding: 0px;
border-radius: 3px;
}
QWidget#controlButtons QPushButton:hover {
background-color: #2A2D2E;
color: #FFFFFF;
}
QPushButton#closeButton {
border-radius: 0px 5px 0px 0px;
}
QPushButton#closeButton:hover {
background-color: #2A2D2E;
color: #FFFFFF;
}
QFrame#titleSeparator {
background-color: #3E3E42;
border: none;
min-height: 1px;
max-height: 1px;
}
QWidget#contentWidget {
background-color: transparent;
border: none;
}
QLabel#iconLabel {
background-color: transparent;
}
QLabel#messageLabel {
background-color: transparent;
color: #EBEBEB;
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
font-size: 13px;
font-weight: 400;
letter-spacing: 0.6px;
line-height: 1.4;
padding: 0px;
margin: 0px;
}
QWidget#buttonWidget {
background-color: transparent;
}
QPushButton {
background-color: rgba(89, 98, 118, 0.5);
color: #EBEBEB;
border: none;
border-radius: 2px;
padding: 0px 12px;
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
font-weight: 300;
font-size: 10px;
letter-spacing: 0.5px;
min-width: 90px;
max-width: 90px;
min-height: 28px;
max-height: 28px;
}
QPushButton:hover {
background-color: #3067C0;
color: #FFFFFF;
}
QPushButton:pressed {
background-color: #2556A0;
color: #FFFFFF;
}
QPushButton#primaryButton {
background-color: rgba(89, 98, 118, 0.5);
border: none;
color: #EBEBEB;
font-weight: 300;
}
QPushButton#primaryButton:hover {
background-color: #2556A0;
}
QPushButton#primaryButton:pressed {
background-color: #1E4A8C;
}
QPushButton#secondaryButton {
background-color: rgba(89, 98, 118, 0.5);
border: none;
color: #EBEBEB;
}
QPushButton#secondaryButton:hover {
background-color: #3067C0;
color: #FFFFFF;
}
QPushButton#secondaryButton:pressed {
background-color: #2556A0;
color: #FFFFFF;
}
""")
def _create_ui(self, message):
"""构建用户界面"""
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
base_frame = QFrame()
base_frame.setObjectName('baseFrame')
base_frame.setFrameShape(QFrame.NoFrame)
base_frame.setAttribute(Qt.WA_StyledBackground, True)
base_layout = QVBoxLayout(base_frame)
base_layout.setContentsMargins(25, 14, 25, 14)
base_layout.setSpacing(0)
self._create_title_bar()
base_layout.addWidget(self.title_bar)
base_layout.addSpacing(4)
title_separator = QFrame()
title_separator.setObjectName('titleSeparator')
title_separator.setFrameShape(QFrame.HLine)
title_separator.setFrameShadow(QFrame.Plain)
base_layout.addWidget(title_separator)
base_layout.addSpacing(10)
content_widget = QWidget()
content_widget.setObjectName('contentWidget')
content_layout = QVBoxLayout(content_widget)
content_layout.setContentsMargins(0, 0, 0, 0)
content_layout.setSpacing(10)
message_area = QHBoxLayout()
message_area.setContentsMargins(0, 0, 0, 0)
message_area.setSpacing(10)
# 用一个垂直布局包裹icon_label确保顶部对齐
icon_vbox = QVBoxLayout()
icon_vbox.setContentsMargins(0, 0, 0, 0)
icon_vbox.setSpacing(0)
icon_label = QLabel()
icon_label.setObjectName('iconLabel')
if self._message_icon and not self._message_icon.isNull():
icon_label.setPixmap(self._message_icon.pixmap(self.icon_size))
icon_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
icon_label.setFixedSize(self.icon_size)
icon_vbox.addWidget(icon_label, alignment=Qt.AlignTop)
icon_vbox.addStretch()
message_area.addLayout(icon_vbox)
self.message_label = QLabel(message)
self.message_label.setObjectName('messageLabel')
self.message_label.setWordWrap(True)
self.message_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
self.message_label.setMinimumHeight(self.icon_size.height())
self.message_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
message_area.addWidget(self.message_label, 1)
message_area.addStretch()
content_layout.addLayout(message_area)
base_layout.addWidget(content_widget)
base_layout.addSpacing(10)
button_widget = QWidget()
button_widget.setObjectName('buttonWidget')
button_layout = QHBoxLayout(button_widget)
button_layout.setContentsMargins(0, 0, 0, 0)
button_layout.setSpacing(10)
button_layout.addStretch()
if self.show_cancel:
self.cancel_button = QPushButton(self.cancel_text)
self.cancel_button.setObjectName("secondaryButton")
self.cancel_button.clicked.connect(self.reject)
self.cancel_button.setFixedSize(90, 28)
button_layout.addWidget(self.cancel_button)
self.confirm_button = QPushButton(self.confirm_text)
self.confirm_button.setObjectName("primaryButton")
self.confirm_button.clicked.connect(self.accept)
self.confirm_button.setFixedSize(90, 28)
button_layout.addWidget(self.confirm_button)
self.confirm_button.setDefault(True)
self.confirm_button.setAutoDefault(True)
if self.show_cancel:
self.cancel_button.setAutoDefault(False)
base_layout.addWidget(button_widget)
main_layout.addWidget(base_frame)
def _create_title_bar(self):
"""创建自定义标题栏"""
self.title_bar = QFrame()
self.title_bar.setObjectName("titleBar")
title_layout = QHBoxLayout(self.title_bar)
title_layout.setContentsMargins(0, 0, 0, 0)
title_layout.setSpacing(0)
self.title_label = QLabel(self.windowTitle())
self.title_label.setObjectName("titleLabel")
self.title_label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
title_layout.addWidget(self.title_label, 1)
title_layout.addStretch()
controls = QWidget()
controls.setObjectName("controlButtons")
controls_layout = QHBoxLayout(controls)
controls_layout.setContentsMargins(0, 0, 0, 0)
controls_layout.setSpacing(0)
self.close_button = QPushButton()
self.close_button.setObjectName("closeButton")
self.close_button.clicked.connect(self.reject)
self.close_button.setFocusPolicy(Qt.NoFocus)
controls_layout.addWidget(self.close_button)
self._apply_title_bar_icons()
title_layout.addWidget(controls)
def _apply_title_bar_icons(self):
"""应用标题栏图标"""
if self._icon_close:
self.close_button.setIcon(self._icon_close)
self.close_button.setIconSize(self._title_icon_size)
self.close_button.setText("")
self.close_button.setToolTip("关闭")
def setWindowTitle(self, title):
"""设置窗口标题"""
super().setWindowTitle(title)
if hasattr(self, "title_label"):
self.title_label.setText(title)
def mousePressEvent(self, event):
"""鼠标按下事件 - 用于拖拽窗口"""
if event.button() == Qt.LeftButton and self.title_bar.geometry().contains(event.pos()):
self.dragging = True
self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
"""鼠标移动事件 - 用于拖拽窗口"""
if event.buttons() == Qt.LeftButton and self.dragging:
self.move(event.globalPos() - self.drag_position)
event.accept()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
"""鼠标释放事件 - 停止拖拽"""
if event.button() == Qt.LeftButton:
self.dragging = False
super().mouseReleaseEvent(event)
@staticmethod
def show_success(parent, title, message, show_cancel=False, confirm_text="确认"):
"""显示成功消息对话框"""
dialog = UniversalMessageDialog(
parent, title, message,
UniversalMessageDialog.SUCCESS,
show_cancel, confirm_text
)
return dialog.exec_()
@staticmethod
def show_warning(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
"""显示警告消息对话框"""
dialog = UniversalMessageDialog(
parent, title, message,
UniversalMessageDialog.WARNING,
show_cancel, confirm_text, cancel_text
)
return dialog.exec_()
@staticmethod
def show_error(parent, title, message, show_cancel=False, confirm_text="确认"):
"""显示错误消息对话框"""
dialog = UniversalMessageDialog(
parent, title, message,
UniversalMessageDialog.ERROR,
show_cancel, confirm_text
)
return dialog.exec_()
@staticmethod
def show_info(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
"""显示信息消息对话框"""
dialog = UniversalMessageDialog(
parent, title, message,
UniversalMessageDialog.INFO,
show_cancel, confirm_text, cancel_text
)
return dialog.exec_()