111 lines
4.0 KiB
C++
111 lines
4.0 KiB
C++
#include "ledindicator.h"
|
|
#include <QPainter>
|
|
#include <QRadialGradient>
|
|
#include <QFontMetrics>
|
|
#include "global.h"
|
|
|
|
QSize LedIndicator::sizeHint() const
|
|
{
|
|
QFont f = font();
|
|
f.setPixelSize(m_textPx);
|
|
const QFontMetrics fm(f);
|
|
const int textW = fm.horizontalAdvance(m_text);
|
|
if (m_dotAfter)
|
|
return QSize(textW + 10 + m_radius * 2 + 10, 52); // 文字 + 间距 + 圆点区 + 右侧 10px
|
|
// 宽度 = 文字起点(圆点区 + 左侧 10px) + 文字宽度 + 右侧 10px
|
|
return QSize(textLeft() + textW + 10, 52); // 高度与构造函数 setFixedHeight(52) 一致
|
|
}
|
|
|
|
LedIndicator::LedIndicator(const QString& text, QWidget* parent)
|
|
: QWidget(parent), m_text(text)
|
|
{
|
|
setFixedHeight(52);
|
|
setAttribute(Qt::WA_TranslucentBackground);
|
|
}
|
|
|
|
void LedIndicator::setState(State s)
|
|
{
|
|
m_state = s;
|
|
const bool needBlink = (s == RedBlink || s == YellowBlink);
|
|
if (needBlink && !m_blinkConn) {
|
|
// 挂全局节拍,而不是本控件自己起定时器:各自起的话相位互不相同,
|
|
// 同一屏上的几个指示灯(顶部通信状态、底栏、自检结果…)会各闪各的。
|
|
m_blinkConn = connect(BlinkBeat::instance(), &BlinkBeat::toggled, this,
|
|
[this](bool on) { m_on = on; update(); });
|
|
m_on = BlinkBeat::instance()->on(); // 立刻对齐当前相位,别等下一拍
|
|
} else if (!needBlink && m_blinkConn) {
|
|
disconnect(m_blinkConn);
|
|
m_blinkConn = QMetaObject::Connection();
|
|
m_on = true; // 停闪=常亮
|
|
}
|
|
update();
|
|
}
|
|
|
|
void LedIndicator::setText(const QString& t)
|
|
{
|
|
m_text = t;
|
|
updateGeometry(); // 文字变了,重新按新宽度请求布局
|
|
update();
|
|
}
|
|
|
|
void LedIndicator::paintEvent(QPaintEvent*)
|
|
{
|
|
QPainter p(this);
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
// 文字度量:圆点位置取决于文字宽度(圆点在文字后时)
|
|
QFont f = p.font();
|
|
f.setPixelSize(m_textPx);
|
|
p.setFont(f);
|
|
const QFontMetrics fm(f);
|
|
const int textW = fm.horizontalAdvance(m_text);
|
|
|
|
// 中心圆点颜色
|
|
QColor color = QColor(C::DISABLED); // 灰
|
|
switch (m_state) {
|
|
case Green: color = QColor(C::SUCCESS); break;
|
|
case Red: color = QColor(C::DANGER); break;
|
|
case Yellow: color = QColor(C::WARNING); break;
|
|
case RedBlink: color = QColor(C::DANGER); break;
|
|
case YellowBlink: color = QColor(C::WARNING); break;
|
|
default: color = QColor(C::DISABLED); break;
|
|
}
|
|
|
|
// 闪烁:40% 透明度
|
|
if ((m_state == RedBlink || m_state == YellowBlink) && !m_on)
|
|
color.setAlpha(102);
|
|
|
|
const QPointF c(m_dotAfter ? textW + 10 + m_radius : m_radius + 8, height() / 2.0);
|
|
|
|
// 外发光
|
|
if (color.alpha() > 0) {
|
|
QRadialGradient glow(c, m_radius + 8);
|
|
QColor g = color; g.setAlpha(color.alpha() / 3);
|
|
QColor g0 = g; g0.setAlpha(0);
|
|
glow.setColorAt(0.0, g);
|
|
glow.setColorAt(1.0, g0);
|
|
p.setPen(Qt::NoPen);
|
|
p.setBrush(glow);
|
|
p.drawEllipse(c, m_radius + 8, m_radius + 8);
|
|
}
|
|
|
|
// 圆形主体(径向渐变)
|
|
QRadialGradient grad(c + QPointF(-m_radius / 3.0, -m_radius / 3.0), m_radius * 1.6);
|
|
QColor hi = color.lighter(130);
|
|
grad.setColorAt(0.0, hi);
|
|
grad.setColorAt(1.0, color);
|
|
p.setBrush(grad);
|
|
p.setPen(QPen(QColor(C::BORDER), 1));
|
|
p.drawEllipse(c, m_radius, m_radius);
|
|
|
|
// 文字(圆点在文字后时,文字从控件左边缘开始)
|
|
QColor textColor = m_textColor.isValid() ? m_textColor : QColor(C::TEXT);
|
|
// 顶部状态条这类要“整条闪烁”的场合:文字与圆点同步降到 40% 透明度
|
|
if (m_blinkText && (m_state == RedBlink || m_state == YellowBlink) && !m_on)
|
|
textColor.setAlpha(102);
|
|
p.setPen(textColor);
|
|
const QRectF textRect(m_dotAfter ? 0 : textLeft(), 0,
|
|
m_dotAfter ? textW : width() - textLeft() - 10, height());
|
|
p.drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, m_text);
|
|
}
|