Files
CalibratorLauncher/widgets/appicon.cpp
2026-01-02 19:20:35 +09:00

284 lines
7.8 KiB
C++
Raw Permalink 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.

#include "appicon.h"
#include <QPainter>
#include <QPainterPath>
#include <QMouseEvent>
#include <QLinearGradient>
#include <QVBoxLayout>
#include <QDebug>
AppIcon::AppIcon(const AppIconData &data, QWidget *parent)
: QWidget(parent), m_data(data), m_scale(1.0), m_isPressed(false), m_longPressTimerId(0)
{
qDebug() << "AppIcon constructor:" << data.name << "(" << data.id << ")";
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setCursor(Qt::PointingHandCursor);
setAttribute(Qt::WA_Hover);
setupUI();
qDebug() << "AppIcon created successfully:" << data.name;
}
AppIcon::~AppIcon()
{
if (m_longPressTimerId)
{
killTimer(m_longPressTimerId);
}
}
void AppIcon::setupUI()
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(3, 3, 3, 3);
layout->setSpacing(5);
layout->setAlignment(Qt::AlignCenter);
// Android风格图标尺寸 - 10英寸屏幕优化
int iconSize = 80;
int borderRadius = 16;
QWidget *iconContainer = new QWidget(this);
iconContainer->setFixedSize(iconSize, iconSize);
iconContainer->setObjectName("iconContainer");
// 设置阴影效果 - 更明显的阴影
m_shadowEffect = new QGraphicsDropShadowEffect(this);
m_shadowEffect->setBlurRadius(16);
m_shadowEffect->setColor(QColor(0, 0, 0, 60));
m_shadowEffect->setOffset(0, 4);
iconContainer->setGraphicsEffect(m_shadowEffect);
// 图标标签
m_iconLabel = new QLabel(iconContainer);
m_iconLabel->setAlignment(Qt::AlignCenter);
m_iconLabel->setFixedSize(iconSize, iconSize);
m_iconLabel->move(0, 0);
// 设置图标样式
QString gradientStart = m_data.gradient.size() > 0 ? m_data.gradient[0] : m_data.color;
QString gradientEnd = m_data.gradient.size() > 1 ? m_data.gradient[1] : m_data.color;
QString iconStyle = QString(R"(
QLabel {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 %1, stop:1 %2);
border-radius: %3px;
font-size: 36px;
color: white;
}
)")
.arg(gradientStart, gradientEnd)
.arg(borderRadius);
m_iconLabel->setStyleSheet(iconStyle);
// 设置 SVG 图标
QString iconPath = getIconSymbol(m_data.id);
if (!iconPath.isEmpty())
{
QPixmap pixmap(iconPath);
if (!pixmap.isNull())
{
// 缩放图标到合适大小
int svgSize = iconSize - 24; // 留出边距
pixmap = pixmap.scaled(svgSize, svgSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_iconLabel->setPixmap(pixmap);
}
}
// 徽章标签 - 过滤掉emoji只显示纯文字badge
if (!m_data.badge.isEmpty())
{
QString badgeText = m_data.badge;
// 过滤掉emoji字符保留ASCII和常见中文字符
QString filteredBadge;
for (const QChar &ch : badgeText)
{
ushort unicode = ch.unicode();
// 保留基本ASCII32-126、中文字符0x4E00-0x9FFF、以及一些常用符号
if ((unicode >= 32 && unicode <= 126) ||
(unicode >= 0x4E00 && unicode <= 0x9FFF) ||
ch == QChar(0xB1) || // ±
ch == QChar(0x394) || // Δ
ch == QChar(0x3A9))
{ // Ω
filteredBadge += ch;
}
}
if (!filteredBadge.isEmpty())
{
m_badgeLabel = new QLabel(iconContainer);
m_badgeLabel->setText(filteredBadge);
m_badgeLabel->setFixedSize(26, 16);
m_badgeLabel->setAlignment(Qt::AlignCenter);
m_badgeLabel->move(iconSize - 28, iconSize - 18);
m_badgeLabel->setStyleSheet(R"(
QLabel {
background-color: rgba(255, 255, 255, 0.95);
color: #333;
border-radius: 4px;
font-size: 9px;
font-weight: bold;
}
)");
}
}
layout->addWidget(iconContainer, 0, Qt::AlignCenter);
// 名称标签 - Android风格白色文字带阴影
m_nameLabel = new QLabel(m_data.name, this);
m_nameLabel->setAlignment(Qt::AlignCenter);
m_nameLabel->setFixedWidth(150);
m_nameLabel->setWordWrap(false);
m_nameLabel->setStyleSheet(R"(
QLabel {
color: white;
font-size: 13px;
font-weight: 500;
background: transparent;
}
)");
layout->addWidget(m_nameLabel, 0, Qt::AlignCenter);
}
QString AppIcon::getIconSymbol(const QString &id) const
{
// 返回对应的SVG图标路径
static QMap<QString, QString> iconMap = {
{"rtd", ":/icons/ic_rtd.svg"},
{"rtd_measure", ":/icons/ic_rtd.svg"},
{"rtd_output", ":/icons/ic_rtd_output.svg"},
{"thermocouple", ":/icons/ic_thermocouple.svg"},
{"insulation", ":/icons/ic_insulation.svg"},
{"dc_current", ":/icons/ic_dc_current.svg"},
{"dc_voltage", ":/icons/ic_dc_voltage.svg"},
{"frequency", ":/icons/ic_frequency.svg"},
{"ac_voltage", ":/icons/ic_ac_voltage.svg"},
{"switch_detect", ":/icons/ic_switch.svg"},
{"ripple", ":/icons/ic_ripple.svg"},
{"ramp", ":/icons/ic_ramp.svg"},
{"waveform", ":/icons/ic_waveform.svg"},
{"dual_channel", ":/icons/ic_dual_channel.svg"},
{"trim", ":/icons/ic_trim.svg"},
{"data_management", ":/icons/ic_data.svg"},
{"wireless", ":/icons/ic_wireless.svg"},
{"sop", ":/icons/ic_sop.svg"},
{"rcp63", ":/icons/ic_rcp63.svg"},
{"settings", ":/icons/ic_settings.svg"},
{"network_test", ":/icons/ic_network_test.svg"},
{"dock_sop", ":/icons/ic_sop.svg"},
{"dock_rcp63", ":/icons/ic_rcp63.svg"},
{"dock_network", ":/icons/ic_network_test.svg"},
{"dock_settings", ":/icons/ic_settings.svg"}};
return iconMap.value(id, "");
}
void AppIcon::setScale(qreal scale)
{
if (qFuzzyCompare(m_scale, scale))
return;
m_scale = scale;
update();
}
void AppIcon::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
if (!qFuzzyCompare(m_scale, 1.0))
{
// 应用缩放变换
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QTransform transform;
transform.translate(width() / 2, height() / 2);
transform.scale(m_scale, m_scale);
transform.translate(-width() / 2, -height() / 2);
painter.setTransform(transform);
}
QWidget::paintEvent(event);
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void AppIcon::enterEvent(QEnterEvent *event)
#else
void AppIcon::enterEvent(QEvent *event)
#endif
{
Q_UNUSED(event)
m_shadowEffect->setBlurRadius(20);
m_shadowEffect->setColor(QColor(0, 0, 0, 60));
}
void AppIcon::leaveEvent(QEvent *event)
{
Q_UNUSED(event)
m_shadowEffect->setBlurRadius(16);
m_shadowEffect->setColor(QColor(0, 0, 0, 40));
}
void AppIcon::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_isPressed = true;
animateScale(0.95);
// 启动长按计时器
m_longPressTimerId = startTimer(LONG_PRESS_DELAY);
}
QWidget::mousePressEvent(event);
}
void AppIcon::mouseReleaseEvent(QMouseEvent *event)
{
if (m_longPressTimerId)
{
killTimer(m_longPressTimerId);
m_longPressTimerId = 0;
}
if (m_isPressed && event->button() == Qt::LeftButton)
{
m_isPressed = false;
animateScale(1.0);
if (rect().contains(event->pos()))
{
emit clicked(m_data.id);
}
}
QWidget::mouseReleaseEvent(event);
}
void AppIcon::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_longPressTimerId)
{
killTimer(m_longPressTimerId);
m_longPressTimerId = 0;
if (m_isPressed)
{
emit longPressed(m_data.id);
}
}
QWidget::timerEvent(event);
}
void AppIcon::animateScale(qreal targetScale, int duration)
{
QPropertyAnimation *anim = new QPropertyAnimation(this, "scale", this);
anim->setDuration(duration);
anim->setStartValue(m_scale);
anim->setEndValue(targetScale);
anim->setEasingCurve(QEasingCurve::OutCubic);
anim->start(QAbstractAnimation::DeleteWhenStopped);
}