match nvg sidebar (#20847)

old-commit-hash: e1a58e6268
commatwo_master
Adeeb Shihadeh 4 years ago committed by GitHub
parent 0375063e3f
commit 7b8f164793
  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 "qt_window.h"
#include "selfdrive/hardware/hw.h" #include "selfdrive/hardware/hw.h"
StatusWidget::StatusWidget(bool has_substatus, QWidget *parent) : QFrame(parent) { void configFont(QPainter &p, QString family, int size, int weight) {
layout = new QVBoxLayout(); QFont f(family);
layout->setSpacing(0); f.setPixelSize(size);
f.setWeight(weight);
status = new QLabel(this); p.setFont(f);
}
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); void Sidebar::drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y) {
substatus->setAlignment(Qt::AlignLeft | Qt::AlignHCenter); const QRect rect = {30, y, 240, val.isEmpty() ? (label.contains("\n") ? 124 : 100) : 148};
substatus->setStyleSheet(R"(font-size: 30px; font-weight: 400;)");
layout->addWidget(status, 0, Qt::AlignLeft); p.setPen(Qt::NoPen);
layout->addWidget(substatus, 0, Qt::AlignLeft); 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 { } else {
layout->setContentsMargins(40, 24, 16, 24); configFont(p, "Open Sans", 58, 500);
p.drawText(rect.x() + 50, rect.y() + 71, val);
status->setAlignment(Qt::AlignCenter); configFont(p, "Open Sans", 35, 400);
status->setStyleSheet(R"(font-size: 38px; font-weight: 500;)"); p.drawText(rect.x() + 50, rect.y() + 50 + 77, label);
layout->addWidget(status, 0, Qt::AlignCenter);
} }
setMinimumHeight(124);
setStyleSheet("background-color: transparent;");
setLayout(layout);
} }
void StatusWidget::paintEvent(QPaintEvent *e) { Sidebar::Sidebar(QWidget *parent) : QFrame(parent) {
QPainter p(this); home_img = QImage("../assets/images/button_home.png").scaled(180, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation);
p.setRenderHint(QPainter::Antialiasing, true); settings_img = QImage("../assets/images/button_settings.png").scaled(settings_btn.width(), settings_btn.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);;
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);
p.setPen(Qt::NoPen); setFixedWidth(300);
p.setBrush(color); setMinimumHeight(vwp_h);
p.setClipRect(0,0,25+6,size().height()-6,Qt::ClipOperation::ReplaceClip); setStyleSheet("background-color: rgb(57, 57, 57);");
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) { void Sidebar::mousePressEvent(QMouseEvent *event) {
status->setText(label); if (settings_btn.contains(event->pos())) {
if (substatus != nullptr) { emit openSettings();
substatus->setText(msg);
} }
if (color != c) {
color = c;
repaint();
}
return;
} }
SignalWidget::SignalWidget(QWidget *parent) : QFrame(parent), _strength(0) { void Sidebar::update(const UIState &s) {
layout = new QVBoxLayout(); if (s.sm->frame % (6*UI_FREQ) == 0) {
layout->setMargin(0); connect_str = "OFFLINE";
layout->setSpacing(0); connect_status = warning_color;
layout->insertSpacing(0, 45); 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();
}
label = new QLabel(this); net_type = s.scene.deviceState.getNetworkType();
label->setStyleSheet(R"(font-size: 35px; font-weight: 400;)"); strength = s.scene.deviceState.getNetworkStrength();
layout->addWidget(label, 0, Qt::AlignLeft);
setFixedWidth(177); temp_status = danger_color;
setLayout(layout); 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;
}
temp_val = (int)s.scene.deviceState.getAmbientTempC();
void SignalWidget::paintEvent(QPaintEvent *e) { panda_str = "VEHICLE\nONLINE";
QPainter p(this); panda_status = good_color;
p.setRenderHint(QPainter::Antialiasing, true); if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
p.setPen(Qt::NoPen); panda_status = danger_color;
p.setBrush(Qt::white); panda_str = "NO\nPANDA";
for (int i = 0; i < 5; i++) { } else if (Hardware::TICI() && s.scene.started) {
if (i == _strength) { panda_str = QString("SAT CNT\n%1").arg(s.scene.satelliteCount);
p.setPen(Qt::NoPen); panda_status = s.scene.gpsOK ? good_color : warning_color;
p.setBrush(Qt::darkGray);
}
p.drawEllipse(QRectF(_dotspace * i, _top, _dia, _dia));
} }
}
void SignalWidget::update(const QString &text, int strength) { if (s.sm->updated("deviceState") || s.sm->updated("pandaState")) {
label->setText(text);
if (_strength != strength) {
_strength = strength;
repaint(); repaint();
} }
} }
Sidebar::Sidebar(QWidget *parent) : QFrame(parent) { void Sidebar::paintEvent(QPaintEvent *event) {
QVBoxLayout *layout = new QVBoxLayout(); QPainter p(this);
layout->setContentsMargins(25, 50, 25, 50); p.setPen(Qt::NoPen);
layout->setSpacing(35); p.setRenderHint(QPainter::Antialiasing);
setFixedSize(300, vwp_h);
// static imgs
QPushButton *s_btn = new QPushButton; p.setOpacity(0.65);
s_btn->setStyleSheet(R"( p.drawImage(settings_btn.x(), settings_btn.y(), settings_img);
border-image: url(../assets/images/button_settings.png); p.setOpacity(1.0);
)"); p.drawImage(60, 1080 - 180 - 40, home_img);
s_btn->setFixedSize(200, 117);
layout->addWidget(s_btn, 0, Qt::AlignHCenter); // network
QObject::connect(s_btn, &QPushButton::pressed, this, &Sidebar::openSettings); p.drawImage(58, 196, signal_imgs[strength]);
configFont(p, "Open Sans", 35, 400);
signal = new SignalWidget(this); p.setPen(QColor(0xff, 0xff, 0xff));
layout->addWidget(signal, 0, Qt::AlignTop | Qt::AlignHCenter); const QRect r = QRect(50, 247, 100, 50);
p.drawText(r, Qt::AlignCenter, network_type[net_type]);
temp = new StatusWidget(true, this);
layout->addWidget(temp, 0, Qt::AlignTop); // metrics
drawMetric(p, "TEMP", QString("%1°C").arg(temp_val), temp_status, 338);
panda = new StatusWidget(false, this); drawMetric(p, panda_str, "", panda_status, 518);
layout->addWidget(panda, 0, Qt::AlignTop); drawMetric(p, "CONNECT\n" + connect_str, "", connect_status, 676);
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;
}
)");
setLayout(layout);
}
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";
if (s.scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
panda_color = COLOR_DANGER;
panda_message = "NO\nPANDA";
}
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);
}
panda->update(panda_message, panda_color);
} }

@ -2,48 +2,7 @@
#include <QtWidgets> #include <QtWidgets>
#include <ui.h> #include "selfdrive/ui/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;
};
class Sidebar : public QFrame { class Sidebar : public QFrame {
Q_OBJECT Q_OBJECT
@ -57,9 +16,42 @@ signals:
public slots: public slots:
void update(const UIState &s); void update(const UIState &s);
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private: private:
SignalWidget *signal; void drawMetric(QPainter &p, const QString &label, const QString &val, QColor c, int y);
StatusWidget *temp;
StatusWidget *panda; QImage home_img, settings_img;
StatusWidget *connect; 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(&qs, &QUIState::offroadTransition, this, &MainWindow::offroadTransition);
QObject::connect(&device, &Device::displayPowerChanged, this, &MainWindow::closeSettings); 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 // no outline to prevent the focus rectangle
setLayout(main_layout); setLayout(main_layout);
setStyleSheet(R"( setStyleSheet(R"(

@ -219,14 +219,8 @@ static void update_state(UIState *s) {
static void update_params(UIState *s) { static void update_params(UIState *s) {
const uint64_t frame = s->sm->frame; const uint64_t frame = s->sm->frame;
UIScene &scene = s->scene; UIScene &scene = s->scene;
Params params;
if (frame % (5*UI_FREQ) == 0) { if (frame % (5*UI_FREQ) == 0) {
scene.is_metric = params.getBool("IsMetric"); 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;
}
} }
} }

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

Loading…
Cancel
Save