brisonus_app_eq/component/widget_card/ui_widget_card.py

196 lines
7.0 KiB
Python
Raw Normal View History

2025-02-18 22:05:52 +08:00
from PySide6.QtWidgets import (QWidget, QListWidget, QStyledItemDelegate,
QApplication, QVBoxLayout, QMenu, QListWidgetItem,
QStyle)
from PySide6.QtCore import Qt, QSize, QRect, QPoint
from PySide6.QtGui import (QPainter, QPainterPath, QColor, QLinearGradient,
QPen, QFont, QIcon)
class CardItemDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__(parent)
self.tree_indent = 20 # 树形缩进距离
self.expanded_items = set() # 跟踪展开状态
2025-02-18 22:05:52 +08:00
def paint(self, painter: QPainter, option, index):
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.save()
# 获取数据
data = index.data(Qt.ItemDataRole.UserRole)
is_expanded = id(data) in self.expanded_items
2025-02-18 22:05:52 +08:00
# 绘制卡片背景
rect = option.rect
rect.adjust(8, 4, -8, -4)
# 创建圆角路径
path = QPainterPath()
path.addRoundedRect(rect, 8, 8)
# 绘制阴影
shadow_color = QColor(0, 0, 0, 30)
for i in range(5):
shadow_rect = rect.adjusted(0, i, 0, i)
shadow_path = QPainterPath()
shadow_path.addRoundedRect(shadow_rect, 8, 8)
painter.fillPath(shadow_path, shadow_color)
# 绘制卡片背景
gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
if data.activated:
gradient.setColorAt(0, QColor(40, 70, 45))
gradient.setColorAt(1, QColor(45, 80, 50))
painter.fillPath(path, gradient)
painter.setPen(QPen(QColor(60, 180, 90), 2))
elif option.state & QStyle.State_Selected:
gradient.setColorAt(0, QColor(45, 45, 55))
gradient.setColorAt(1, QColor(55, 55, 65))
painter.fillPath(path, gradient)
painter.setPen(QPen(QColor(70, 130, 180), 2))
else:
painter.fillPath(path, QColor(35, 35, 40))
painter.setPen(QPen(QColor(60, 60, 65)))
painter.drawPath(path)
# 计算文本区域
padding = 15
name_rect = rect.adjusted(padding, padding, -padding, 0)
name_rect.setHeight(25)
# 绘制展开/折叠图标
if data.params:
icon_size = 16
icon_rect = QRect(
name_rect.left(),
name_rect.top() + (name_rect.height() - icon_size) // 2,
icon_size,
icon_size
)
painter.setPen(QPen(QColor(160, 160, 160), 1))
painter.setBrush(Qt.BrushStyle.NoBrush)
# 绘制小方框
painter.drawRect(icon_rect)
# 绘制横线
h_line_y = icon_rect.center().y()
painter.drawLine(
icon_rect.left() + 3,
h_line_y,
icon_rect.right() - 3,
h_line_y
)
# 绘制竖线(如果未展开)
if not is_expanded:
v_line_x = icon_rect.center().x()
painter.drawLine(
v_line_x,
icon_rect.top() + 3,
v_line_x,
icon_rect.bottom() - 3
)
name_rect.setLeft(icon_rect.right() + 5)
# 绘制基本信息
painter.setFont(QFont("Microsoft YaHei", 10, QFont.Weight.Bold))
2025-02-18 22:05:52 +08:00
painter.setPen(Qt.GlobalColor.white)
painter.drawText(name_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, data.name)
date_rect = QRect(name_rect)
date_rect.translate(0, name_rect.height())
painter.setFont(QFont("Microsoft YaHei", 9))
2025-02-18 22:05:52 +08:00
painter.setPen(QColor(180, 180, 180))
painter.drawText(date_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, data.date)
desc_rect = QRect(date_rect)
desc_rect.translate(0, date_rect.height())
desc_rect.setHeight(40)
2025-02-18 22:05:52 +08:00
painter.setPen(QColor(160, 160, 160))
painter.drawText(desc_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop | Qt.TextFlag.TextWordWrap,
data.description)
# 如果展开,绘制参数
if is_expanded and data.params:
param_start_y = desc_rect.bottom() + 10
param_font = QFont("Microsoft YaHei", 9)
painter.setFont(param_font)
for i, param in enumerate(data.params):
param_rect = QRect(
name_rect.left() + self.tree_indent,
param_start_y + i * 25,
rect.width() - 2 * padding - self.tree_indent,
20
)
# 绘制连接线
line_start_x = name_rect.left() + self.tree_indent // 2
line_end_x = param_rect.left()
line_y = param_rect.center().y()
painter.setPen(QPen(QColor(80, 80, 80), 1))
# 绘制垂直线
if i == 0:
painter.drawLine(
line_start_x,
desc_rect.bottom() + 5,
line_start_x,
param_start_y + (len(data.params) - 1) * 25 + 10
)
# 绘制水平线
painter.drawLine(
line_start_x,
line_y,
line_end_x,
line_y
)
# 绘制参数文本
painter.setPen(QColor(140, 140, 140))
param_text = f"{param.name}: {param.value}"
painter.drawText(param_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, param_text)
2025-02-18 22:05:52 +08:00
painter.restore()
def sizeHint(self, option, index):
data = index.data(Qt.ItemDataRole.UserRole)
base_height = 130
if id(data) in self.expanded_items and data.params:
param_height = len(data.params) * 25
return QSize(380, base_height + param_height + 10)
return QSize(380, base_height)
def editorEvent(self, event, model, option, index):
if event.type() == event.Type.MouseButtonPress:
data = index.data(Qt.ItemDataRole.UserRole)
if not data.params:
return False
rect = option.rect
padding = 15
icon_size = 16
icon_rect = QRect(
rect.left() + padding,
rect.top() + padding + (25 - icon_size) // 2,
icon_size,
icon_size
)
if icon_rect.contains(event.pos()):
if id(data) in self.expanded_items:
self.expanded_items.remove(id(data))
else:
self.expanded_items.add(id(data))
model.dataChanged.emit(index, index)
return True
return False