match nvg sidebar (#20847)

pull/20856/head
Adeeb Shihadeh 4 years ago committed by GitHub
parent 26e518a6af
commit e1a58e6268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 251
      selfdrive/ui/qt/sidebar.cc
  2. 84
      selfdrive/ui/qt/sidebar.h
  3. 5
      selfdrive/ui/qt/window.cc
  4. 8
      selfdrive/ui/ui.cc
  5. 7
      selfdrive/ui/ui.h

@ -3,185 +3,116 @@
#include "qt_window.h"
#include "selfdrive/hardware/hw.h"
StatusWidget::StatusWidget(bool has_substatus, QWidget *parent) : QFrame(parent) {
layout = new QVBoxLayout();
layout->setSpacing(0);
status = new QLabel(this);
if (has_substatus) {
layout->setContentsMargins(50, 24, 16, 24);
status->setAlignment(Qt::AlignLeft | Qt::AlignHCenter);
status->setStyleSheet(R"(font-size: 65px; font-weight: 500;)");
substatus = new QLabel(this);
substatus->setAlignment(Qt::AlignLeft | Qt::AlignHCenter);
substatus->setStyleSheet(R"(font-size: 30px; font-weight: 400;)");
layout->addWidget(status, 0, Qt::AlignLeft);
layout->addWidget(substatus, 0, Qt::AlignLeft);
} else {
layout->setContentsMargins(40, 24, 16, 24);
status->setAlignment(Qt::AlignCenter);
status->setStyleSheet(R"(font-size: 38px; font-weight: 500;)");
layout->addWidget(status, 0, Qt::AlignCenter);
}
setMinimumHeight(124);
setStyleSheet("background-color: transparent;");
setLayout(layout);
void configFont(QPainter &p, QString family, int size, int weight) {
QFont f(family);
f.setPixelSize(size);
f.setWeight(weight);
p.setFont(f);
}
void StatusWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(QPen(QColor(0xb2b2b2), 3, Qt::SolidLine, Qt::FlatCap));
// origin at 1.5,1.5 because qt issues with pixel perfect borders
p.drawRoundedRect(QRectF(1.5, 1.5, size().width()-3, size().height()-3), 30, 30);
void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) {
const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148};
p.setPen(Qt::NoPen);
p.setBrush(color);
p.setClipRect(0,0,25+6,size().height()-6,Qt::ClipOperation::ReplaceClip);
p.drawRoundedRect(QRectF(6, 6, size().width()-12, size().height()-12), 25, 25);
}
void StatusWidget::update(const QString &label, const QColor &c, const QString &msg) {
status->setText(label);
if (substatus != nullptr) {
substatus->setText(msg);
}
if (color != c) {
color = c;
repaint();
p.setBrush(QBrush(c));
p.setClipRect(rect.x() + 6, rect.y(), 18, rect.height(), Qt::ClipOperation::ReplaceClip);
p.drawRoundedRect(QRect(rect.x() + 6, rect.y() + 6, 100, rect.height() - 12), 10, 10);
p.setClipping(false);
QPen pen = QPen(QColor(0xff, 0xff, 0xff, 0x55));
pen.setWidth(2);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
p.drawRoundedRect(rect, 20, 20);
p.setPen(QColor(0xff, 0xff, 0xff));
if (val.isEmpty()) {
configFont(p, "Open Sans", 35, 500);
const QRect r = QRect(rect.x() + 35, rect.y(), rect.width() - 50, rect.height());
p.drawText(r, Qt::AlignCenter, label);
} else {
configFont(p, "Open Sans", 58, 500);
p.drawText(rect.x() + 50, rect.y() + 71, val);
configFont(p, "Open Sans", 35, 400);
p.drawText(rect.x() + 50, rect.y() + 50 + 77, label);
}
return;
}
SignalWidget::SignalWidget(QWidget *parent) : QFrame(parent), _strength(0) {
layout = new QVBoxLayout();
layout->setMargin(0);
layout->setSpacing(0);
layout->insertSpacing(0, 45);
label = new QLabel(this);
label->setStyleSheet(R"(font-size: 35px; font-weight: 400;)");
layout->addWidget(label, 0, Qt::AlignLeft);
Sidebar::Sidebar(QWidget *parent) : QFrame(parent) {
home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation);
settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);;
setFixedWidth(177);
setLayout(layout);
setFixedWidth(300);
setMinimumHeight(vwp_h);
setStyleSheet("background-color: rgb(57, 57, 57);");
}
void SignalWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(Qt::NoPen);
p.setBrush(Qt::white);
for (int i = 0; i < 5; i++) {
if (i == _strength) {
p.setPen(Qt::NoPen);
p.setBrush(Qt::darkGray);
}
p.drawEllipse(QRectF(_dotspace * i, _top, _dia, _dia));
void Sidebar::mousePressEvent(QMouseEvent *event) {
if (settings_btn.contains(event->pos())) {
emit openSettings();
}
}
void SignalWidget::update(const QString &text, int strength) {
label->setText(text);
if (_strength != strength) {
_strength = strength;
void Sidebar::update(const UIState &s) {
if (s.sm->frame % (6*UI_FREQ) == 0) {
connect_str = "OFFLINE";
connect_status = warning_color;
auto last_ping = params.get<float>("LastAthenaPingTime");
if (last_ping) {
bool online = nanos_since_boot() - *last_ping < 70e9;
connect_str = online ? "ONLINE" : "ERROR";
connect_status = online ? good_color : danger_color;
}
repaint();
}
}
Sidebar::Sidebar(QWidget *parent) : QFrame(parent) {
QVBoxLayout *layout = new QVBoxLayout();
layout->setContentsMargins(25, 50, 25, 50);
layout->setSpacing(35);
setFixedSize(300, vwp_h);
QPushButton *s_btn = new QPushButton;
s_btn->setStyleSheet(R"(
border-image: url(../assets/images/button_settings.png);
)");
s_btn->setFixedSize(200, 117);
layout->addWidget(s_btn, 0, Qt::AlignHCenter);
QObject::connect(s_btn, &QPushButton::pressed, this, &Sidebar::openSettings);
signal = new SignalWidget(this);
layout->addWidget(signal, 0, Qt::AlignTop | Qt::AlignHCenter);
temp = new StatusWidget(true, this);
layout->addWidget(temp, 0, Qt::AlignTop);
panda = new StatusWidget(false, this);
layout->addWidget(panda, 0, Qt::AlignTop);
connect = new StatusWidget(false, this);
layout->addWidget(connect, 0, Qt::AlignTop);
QImage image = QImageReader("../assets/images/button_home.png").read();
QLabel *comma = new QLabel(this);
comma->setPixmap(QPixmap::fromImage(image));
comma->setAlignment(Qt::AlignCenter);
layout->addWidget(comma, 1, Qt::AlignHCenter | Qt::AlignVCenter);
layout->addStretch(1);
setStyleSheet(R"(
Sidebar {
background-color: #393939;
}
* {
color: white;
net_type = s.scene.deviceState.getNetworkType();
strength = s.scene.deviceState.getNetworkStrength();
temp_status = danger_color;
auto ts = s.scene.deviceState.getThermalStatus();
if (ts == cereal::DeviceState::ThermalStatus::GREEN) {
temp_status = good_color;
} else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) {
temp_status = warning_color;
}
)");
setLayout(layout);
}
temp_val = (int)s.scene.deviceState.getAmbientTempC();
void Sidebar::update(const UIState &s) {
static std::map<NetStatus, std::pair<QString, QColor>> connectivity_map = {
{NET_ERROR, {"CONNECT\nERROR", COLOR_DANGER}},
{NET_CONNECTED, {"CONNECT\nONLINE", COLOR_GOOD}},
{NET_DISCONNECTED, {"CONNECT\nOFFLINE", COLOR_WARNING}},
};
auto net_params = connectivity_map[s.scene.athenaStatus];
connect->update(net_params.first, net_params.second);
static std::map<cereal::DeviceState::ThermalStatus, QColor> temp_severity_map = {
{cereal::DeviceState::ThermalStatus::GREEN, COLOR_GOOD},
{cereal::DeviceState::ThermalStatus::YELLOW, COLOR_WARNING},
{cereal::DeviceState::ThermalStatus::RED, COLOR_DANGER},
{cereal::DeviceState::ThermalStatus::DANGER, COLOR_DANGER}};
QString temp_val = QString("%1 °C").arg((int)s.scene.deviceState.getAmbientTempC());
temp->update(temp_val, temp_severity_map[s.scene.deviceState.getThermalStatus()], "TEMP");
static std::map<cereal::DeviceState::NetworkType, const char *> network_type_map = {
{cereal::DeviceState::NetworkType::NONE, "--"},
{cereal::DeviceState::NetworkType::WIFI, "WiFi"},
{cereal::DeviceState::NetworkType::CELL2_G, "2G"},
{cereal::DeviceState::NetworkType::CELL3_G, "3G"},
{cereal::DeviceState::NetworkType::CELL4_G, "4G"},
{cereal::DeviceState::NetworkType::CELL5_G, "5G"}};
const char *network_type = network_type_map[s.scene.deviceState.getNetworkType()];
static std::map<cereal::DeviceState::NetworkStrength, int> network_strength_map = {
{cereal::DeviceState::NetworkStrength::UNKNOWN, 1},
{cereal::DeviceState::NetworkStrength::POOR, 2},
{cereal::DeviceState::NetworkStrength::MODERATE, 3},
{cereal::DeviceState::NetworkStrength::GOOD, 4},
{cereal::DeviceState::NetworkStrength::GREAT, 5}};
const int img_idx = s.scene.deviceState.getNetworkType() == cereal::DeviceState::NetworkType::NONE ? 0 : network_strength_map[s.scene.deviceState.getNetworkStrength()];
signal->update(network_type, img_idx);
QColor panda_color = COLOR_GOOD;
QString panda_message = "VEHICLE\nONLINE";
panda_str = "VEHICLE\nONLINE";
panda_status = good_color;
if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
panda_color = COLOR_DANGER;
panda_message = "NO\nPANDA";
panda_status = danger_color;
panda_str = "NO\nPANDA";
} else if (Hardware::TICI() && s.scene.started) {
panda_str = QString("SAT CNT\n%1").arg(s.scene.satelliteCount);
panda_status = s.scene.gpsOK ? good_color : warning_color;
}
else if (Hardware::TICI() && s.scene.started) {
panda_color = s.scene.gpsOK ? COLOR_GOOD : COLOR_WARNING;
panda_message = QString("SAT CNT\n%1").arg(s.scene.satelliteCount);
if (s.sm->updated("deviceState") || s.sm->updated("pandaState")) {
repaint();
}
panda->update(panda_message, panda_color);
}
void Sidebar::paintEvent(QPaintEvent *event) {
QPainter p(this);
p.setPen(Qt::NoPen);
p.setRenderHint(QPainter::Antialiasing);
// static imgs
p.setOpacity(0.65);
p.drawImage(settings_btn.x(), settings_btn.y(), settings_img);
p.setOpacity(1.0);
p.drawImage(60, 1080 - 180 - 40, home_img);
// network
p.drawImage(58, 196, signal_imgs[strength]);
configFont(p, "Open Sans", 35, 400);
p.setPen(QColor(0xff, 0xff, 0xff));
const QRect r = QRect(50, 247, 100, 50);
p.drawText(r, Qt::AlignCenter, network_type[net_type]);
// metrics
drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338);
drawMetric(p, panda_str, "", panda_status, 518);
drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676);
}

@ -2,48 +2,7 @@
#include <QtWidgets>
#include <ui.h>
#define COLOR_GOOD QColor(255, 255, 255)
#define COLOR_WARNING QColor(218, 202, 37)
#define COLOR_DANGER QColor(201, 34, 49)
class SignalWidget : public QFrame {
Q_OBJECT
public:
SignalWidget(QWidget* parent = 0);
void update(const QString &text, int strength);
QLabel *label;
int _strength = 0;
protected:
void paintEvent(QPaintEvent*) override;
private:
QVBoxLayout *layout;
const float _dotspace = 37; // spacing between dots
const float _top = 10;
const float _dia = 28; // dot diameter
};
class StatusWidget : public QFrame {
Q_OBJECT
public:
StatusWidget(bool has_substatus, QWidget* parent = 0);
void update(const QString &label, const QColor &c, const QString &msg = "");
protected:
void paintEvent(QPaintEvent*) override;
private:
QLabel *status;
QLabel *substatus = nullptr;
QColor color = COLOR_WARNING;
QVBoxLayout *layout;
};
#include "selfdrive/ui/ui.h"
class Sidebar : public QFrame {
Q_OBJECT
@ -57,9 +16,42 @@ signals:
public slots:
void update(const UIState &s);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private:
SignalWidget *signal;
StatusWidget *temp;
StatusWidget *panda;
StatusWidget *connect;
void drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y);
QImage home_img, settings_img;
const QMap<cereal::DeviceState::NetworkType, QString> network_type = {
{cereal::DeviceState::NetworkType::NONE, "--"},
{cereal::DeviceState::NetworkType::WIFI, "WiFi"},
{cereal::DeviceState::NetworkType::CELL2_G, "2G"},
{cereal::DeviceState::NetworkType::CELL3_G, "3G"},
{cereal::DeviceState::NetworkType::CELL4_G, "4G"},
{cereal::DeviceState::NetworkType::CELL5_G, "5G"}
};
const QMap<cereal::DeviceState::NetworkStrength, QImage> signal_imgs = {
{cereal::DeviceState::NetworkStrength::UNKNOWN, QImage("../assets/images/network_0.png")},
{cereal::DeviceState::NetworkStrength::POOR, QImage("../assets/images/network_1.png")},
{cereal::DeviceState::NetworkStrength::MODERATE, QImage("../assets/images/network_2.png")},
{cereal::DeviceState::NetworkStrength::GOOD, QImage("../assets/images/network_3.png")},
{cereal::DeviceState::NetworkStrength::GREAT, QImage("../assets/images/network_4.png")},
};
const QRect settings_btn = QRect(50, 35, 200, 117);
const QColor good_color = QColor(255, 255, 255);
const QColor warning_color = QColor(218, 202, 37);
const QColor danger_color = QColor(201, 34, 49);
Params params;
QString connect_str = "OFFLINE";
QColor connect_status = warning_color;
QString panda_str = "NO\nPANDA";
QColor panda_status = warning_color;
int temp_val = 0;
QColor temp_status = warning_color;
cereal::DeviceState::NetworkType net_type;
cereal::DeviceState::NetworkStrength strength;
};

@ -32,6 +32,11 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
QObject::connect(&qs, &QUIState::offroadTransition, this, &MainWindow::offroadTransition);
QObject::connect(&device, &Device::displayPowerChanged, this, &MainWindow::closeSettings);
// load fonts
QFontDatabase::addApplicationFont("../assets/fonts/opensans_regular.ttf");
QFontDatabase::addApplicationFont("../assets/fonts/opensans_bold.ttf");
QFontDatabase::addApplicationFont("../assets/fonts/opensans_semibold.ttf");
// no outline to prevent the focus rectangle
setLayout(main_layout);
setStyleSheet(R"(

@ -219,14 +219,8 @@ static void update_state(UIState *s) {
static void update_params(UIState *s) {
const uint64_t frame = s->sm->frame;
UIScene &scene = s->scene;
Params params;
if (frame % (5*UI_FREQ) == 0) {
scene.is_metric = params.getBool("IsMetric");
} else if (frame % (6*UI_FREQ) == 0) {
scene.athenaStatus = NET_DISCONNECTED;
if (auto last_ping = params.get<float>("LastAthenaPingTime"); last_ping) {
scene.athenaStatus = nanos_since_boot() - *last_ping < 70e9 ? NET_CONNECTED : NET_ERROR;
}
scene.is_metric = Params().getBool("IsMetric");
}
}

@ -48,12 +48,6 @@ const int footer_h = 280;
const int UI_FREQ = 20; // Hz
typedef enum NetStatus {
NET_CONNECTED,
NET_DISCONNECTED,
NET_ERROR,
} NetStatus;
typedef enum UIStatus {
STATUS_DISENGAGED,
STATUS_ENGAGED,
@ -86,7 +80,6 @@ typedef struct UIScene {
bool driver_view;
cereal::PandaState::PandaType pandaType;
NetStatus athenaStatus;
cereal::DeviceState::Reader deviceState;
cereal::RadarState::LeadData::Reader lead_data[2];

Loading…
Cancel
Save