brisonus_app_eq/component/widget_card/ui_widget_card.py

196 lines
7.0 KiB
Python

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() # 跟踪展开状态
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
# 绘制卡片背景
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))
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))
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)
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)
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