Files
2026-10-16 09:06:03 +08:00

139 lines
5.5 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 "titlebar.h"
#include "ledindicator.h"
#include "appcontext.h"
#include "car.h"
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include "global.h"
namespace {
// 首页/作业选择“中央卡片区”的左边缘:主区左内边距 24 + 左列 300 + 间距 24
const int kCardLeft = 300;
// LedIndicator 的文字起点(圆点区宽度):radius(16)×2 + 左侧留白 18,见 LedIndicator::textLeft()
const int kCommTextLeft = 50;
// 顶栏左右区宽度。左区要容下最长的一条异常“气体检测仪通信异常”
// (9 个全角字 × 43px = 387):274(左侧留白) + 50 + 387 + 10 = 721;
// 上限 726——居中标题的左边缘在 750,再宽就压上去了。
const int kSideW = 726;
} // namespace
TitleBar::TitleBar(AppContext* ctx, QWidget* parent)
: QWidget(parent), m_ctx(ctx)
{
setObjectName("TitleBar");
setFixedHeight(98);
setStyleSheet(QString("QWidget#TitleBar{background-color:%1;border-bottom:1px solid %2;}")
.arg(C::PANEL, C::BORDER));
// 左侧区(车载端通信状态,固定一行,不轮播)
QWidget* leftBox = new QWidget(this);
QHBoxLayout* leftLay = new QHBoxLayout(leftBox);
leftLay->setSpacing(0); // 只有指示器 + 弹簧,留间距只会白白吃掉文字宽度
m_comm = new LedIndicator("系统通信正常", leftBox);
// 高度沿用 LedIndicator 默认的 52:43px 字与 48px 直径的圆点外发光刚好容得下
m_comm->setTextPixelSize(45); // 与右侧“遥控器正常”同字号
m_comm->setBlinkText(true); // 异常时文字跟着圆点一起闪
m_comm->setState(LedIndicator::Green);
leftLay->setContentsMargins(kCardLeft - 24 - kCommTextLeft, 0, 0, 0);
leftLay->addWidget(m_comm, 0, Qt::AlignLeft | Qt::AlignVCenter);
leftLay->addStretch(1);
// 右侧区(遥控器状态:链路 + 电量)
QWidget* rightBox = new QWidget(this);
QHBoxLayout* rightLay = new QHBoxLayout(rightBox);
rightLay->setContentsMargins(0, 0, 20, 0);
rightLay->setSpacing(30);
rightLay->addStretch(1);
m_rc = new LedIndicator("遥控器断开", rightBox);
m_rc->setFixedHeight(80);
m_rc->setTextPixelSize(45);
m_rc->setState(LedIndicator::RedBlink);
rightLay->addWidget(m_rc);
m_rcBat = new QLabel(rightBox);
m_rcBat->setAlignment(Qt::AlignCenter);
rightLay->addWidget(m_rcBat);
setRcBattery(-1);
// 左右两侧区等宽(宽度见 kSideW:左区要放得下最长的一条异常)
leftBox->setFixedWidth(kSideW);
rightBox->setFixedWidth(kSideW);
// 标题(居中)
m_title = new QLabel("", this);
m_title->setAlignment(Qt::AlignCenter);
m_title->setStyleSheet(QString("color:%1;font-size:60px;font-weight:700;").arg(C::TEXT));
// 用 QGridLayout 让标题横跨整条顶栏居中,而不是夹在左右两区之间拉伸:
// 后者下标题的可用宽度 = 1920 - 24×2 - 两侧区宽×2,左区为了放下通信文字一加宽,
// 标题就被挤窄甚至裁字;横跨三列后标题始终居中于屏幕,两侧区多宽都不影响它。
QGridLayout* lay = new QGridLayout(this);
lay->setContentsMargins(24, 6, 24, 6);
lay->setSpacing(0);
lay->addWidget(leftBox, 0, 0, Qt::AlignLeft | Qt::AlignVCenter);
lay->addWidget(rightBox, 0, 2, Qt::AlignRight | Qt::AlignVCenter);
lay->addWidget(m_title, 0, 0, 1, 3, Qt::AlignCenter);
// 车载端通信状态:只在文案变化时由通信层通知,这里不做任何轮播。
connect(m_ctx->comm(), &CarCommunication::commTextChanged,
this, &TitleBar::onCommTextChanged);
// 每个页面各有自己的顶条实例,构造时通信层可能早就报过状态了;而 commTextChanged
// 只在内容变化时才发,所以这里必须先取一次当前值,否则新页面的顶条会一直停在构造时的初值。
updateComm();
// 遥控器链路与电量刷新
connect(m_ctx->rc(), &RcCommunication::linkChanged, this, &TitleBar::onRcLink);
connect(m_ctx->rc(), &RcCommunication::frameReceived, this, &TitleBar::onRcFrame);
onRcLink(m_ctx->rc()->linkOk());
}
void TitleBar::onCommTextChanged()
{
updateComm();
}
// 左区固定显示通信状态:链路断或带 All_Comm_FaultCode 就红色闪烁,其余绿灯。
// 文案由通信层渲染(Telemetry::commText),这里只决定配色。
void TitleBar::updateComm()
{
const Telemetry& t = m_ctx->telemetry;
const bool warn = !t.commOk || t.commCode != 0;
m_comm->setText(t.commText);
m_comm->setState(warn ? LedIndicator::RedBlink : LedIndicator::Green);
m_comm->setTextColor(QColor(warn ? C::DANGER : C::TEXT)); // 只有异常才用红色警示
}
void TitleBar::setTitle(const QString& title)
{
m_title->setText(title);
}
void TitleBar::onRcLink(bool ok)
{
if (ok) {
m_rc->setText("遥控器正常");
m_rc->setState(LedIndicator::Green);
} else {
m_rc->setText("遥控器断开");
m_rc->setState(LedIndicator::RedBlink);
setRcBattery(-1);
}
}
void TitleBar::setRcBattery(int battery)
{
// battery < 0 表示链路断开,无电量可显示
const bool valid = battery >= 0;
const QString color = !valid ? C::TEXT_SUB
: (battery <= 20 ? C::DANGER : C::SUCCESS);
m_rcBat->setText(valid ? QString("%1%").arg(battery) : QString("--%"));
m_rcBat->setStyleSheet(QString("color:%1;font-size:50px;").arg(color));
}
void TitleBar::onRcFrame(const RcFrame& f)
{
setRcBattery(f.battery);
}