Files
nl-utils/v1/views/app_center.py
2025-06-07 15:54:17 +08:00

258 lines
8.1 KiB
Python

import math
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QFrame, QGridLayout, QSpacerItem)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QPixmap, QIcon, QColor, QLinearGradient, QBrush, QPainter
from PyQt5.QtCore import QRectF
class GradientFrame(QFrame):
def __init__(self, start_color, end_color, angle=0, parent=None):
super().__init__(parent)
self.start_color = QColor(start_color)
self.end_color = QColor(end_color)
self.angle = angle # 0-360 degrees
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
gradient = QLinearGradient(0, 0, self.width(), self.height())
if self.angle == 0:
gradient = QLinearGradient(0, 0, self.width(), 0)
elif self.angle == 90:
gradient = QLinearGradient(0, 0, 0, self.height())
elif self.angle == 180:
gradient = QLinearGradient(self.width(), 0, 0, 0)
elif self.angle == 270:
gradient = QLinearGradient(0, self.height(), 0, 0)
else:
# Angle between 0 and 360
rad = self.angle * 3.14159 / 180.0
cx = self.width() / 2
cy = self.height() / 2
radius = max(self.width(), self.height())
start_x = cx + radius * 0.5 * math.cos(rad)
start_y = cy + radius * 0.5 * math.sin(rad)
end_x = cx - radius * 0.5 * math.cos(rad)
end_y = cy - radius * 0.5 * math.sin(rad)
gradient = QLinearGradient(start_x, start_y, end_x, end_y)
gradient.setColorAt(0, self.start_color)
gradient.setColorAt(1, self.end_color)
painter.fillRect(self.rect(), QBrush(gradient))
super().paintEvent(event)
class AppCenter(QWidget):
app_selected = pyqtSignal(str)
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setObjectName("appCenter")
self.setStyleSheet("""
#appCenter {
background-color: #1a202c;
}
#pageTitle {
font-size: 28px;
font-weight: bold;
color: white;
margin-bottom: 30px;
}
#appCard {
border-radius: 12px;
background-color: #2d3748;
border: 1px solid #4a5568;
transition: transform 0.2s, box-shadow 0.2s;
}
#appCard:hover {
transform: translateY(-5px);
background-color: #3c4657;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.25);
}
#appCardTitle {
font-size: 20px;
font-weight: bold;
color: white;
text-align: center;
margin-top: 15px;
}
#appCardDesc {
font-size: 14px;
color: #cbd5e0;
text-align: center;
padding: 0 10px;
}
#appCardBtn {
background-color: #4f46e5;
color: white;
border-radius: 6px;
padding: 10px 16px;
font-weight: 600;
border: none;
min-width: 120px;
}
#appCardBtn:hover {
background-color: #4338ca;
}
""")
layout = QVBoxLayout()
layout.setContentsMargins(40, 30, 40, 30)
layout.setSpacing(20)
# 标题区域
title_layout = QHBoxLayout()
title = QLabel("应用中心")
title.setObjectName("pageTitle")
title_spacer = QSpacerItem(40, 20)
title_layout.addWidget(title)
title_layout.addSpacerItem(title_spacer)
layout.addLayout(title_layout)
# 卡片容器
grid_layout = QVBoxLayout()
grid_layout.setSpacing(20)
# 应用卡片
apps = [
{
"id": "word_to_pdf",
"title": "Word转PDF",
"desc": "批量将Word文档转换为PDF格式",
"color": ("#6366F1", "#4F46E5") # 渐变开始和结束颜色
},
{
"id": "ocr",
"title": "OCR文字识别",
"desc": "从图片中提取文字内容",
"color": ("#4ADE80", "#22C55E")
},
{
"id": "image_convert",
"title": "图片格式转换",
"desc": "转换图像文件格式并优化",
"color": ("#F97316", "#EA580C")
},
{
"id": "coming_soon",
"title": "敬请期待",
"desc": "更多实用功能正在开发中",
"color": ("#8B5CF6", "#7C3AED")
}
]
# 每行显示2张卡片
for i in range(0, len(apps), 2):
row_layout = QHBoxLayout()
row_layout.setSpacing(30)
for j in range(2):
index = i + j
if index < len(apps):
row_layout.addWidget(self.create_app_card(apps[index]))
else:
# 添加空白占位符保持布局
spacer = QSpacerItem(0, 0)
row_layout.addItem(spacer)
grid_layout.addLayout(row_layout)
layout.addLayout(grid_layout)
layout.addStretch()
self.setLayout(layout)
def create_app_card(self, app):
"""创建应用卡片"""
card = GradientFrame(app["color"][0], app["color"][1], 45)
card.setObjectName("appCard")
card.setFixedSize(300, 280)
layout = QVBoxLayout(card)
layout.setContentsMargins(20, 20, 20, 20)
layout.setSpacing(15)
# 图标
icon_frame = QFrame()
icon_frame.setFixedSize(80, 80)
icon_frame.setStyleSheet("background-color: rgba(255, 255, 255, 0.2); border-radius: 40px;")
icon_frame.setObjectName("appCardIcon")
icon_layout = QVBoxLayout(icon_frame)
icon_layout.setContentsMargins(0, 0, 0, 0)
# 使用QSS设置图标颜色为白色
icon = QLabel()
icon_pixmap = QPixmap(f":/icons/{app['id']}.png").scaled(48, 48,
Qt.KeepAspectRatio,
Qt.SmoothTransformation)
# 转换图标为白色
if app["id"] != "coming_soon":
painter = QPainter(icon_pixmap)
painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
painter.fillRect(icon_pixmap.rect(), Qt.white)
painter.end()
icon.setPixmap(icon_pixmap)
icon.setAlignment(Qt.AlignCenter)
icon_layout.addWidget(icon)
layout.addWidget(icon_frame, 0, Qt.AlignHCenter)
# 标题
title = QLabel(app["title"])
title.setObjectName("appCardTitle")
layout.addWidget(title)
# 描述
desc = QLabel(app["desc"])
desc.setObjectName("appCardDesc")
desc.setWordWrap(True)
layout.addWidget(desc)
# 添加伸缩空间保持底部对齐
spacer = QSpacerItem(20, 20)
layout.addItem(spacer)
# 按钮
btn_text = "开始使用" if app["id"] != "coming_soon" else "敬请期待"
btn = QPushButton(btn_text)
btn.setObjectName("appCardBtn")
btn.setCursor(Qt.PointingHandCursor)
if app["id"] == "coming_soon":
btn.setEnabled(False)
btn.setStyleSheet("""
#appCardBtn:disabled {
background-color: rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.7);
}
""")
else:
btn.clicked.connect(lambda: self.app_selected.emit(app["id"]))
layout.addWidget(btn, 0, Qt.AlignHCenter)
# 为卡片添加点击事件
card.mousePressEvent = lambda e: self.app_selected.emit(app["id"]) if app["id"] != "coming_soon" else None
return card