* revive #19877

* looks like a sidebar

* more like a sidebar

* cleanup

* fix qcom2

* style

* that's the sidebar

* more space

Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: db9319405b
commatwo_master
Adeeb Shihadeh 4 years ago committed by GitHub
parent 002057e1f1
commit f5e6a0c9a0
  1. 2
      selfdrive/ui/SConscript
  2. 12
      selfdrive/ui/paint.cc
  3. 2
      selfdrive/ui/paint.hpp
  4. 44
      selfdrive/ui/qt/home.cc
  5. 11
      selfdrive/ui/qt/home.hpp
  6. 6
      selfdrive/ui/qt/onroad.cc
  7. 1
      selfdrive/ui/qt/onroad.hpp
  8. 177
      selfdrive/ui/qt/sidebar.cc
  9. 65
      selfdrive/ui/qt/sidebar.hpp
  10. 143
      selfdrive/ui/sidebar.cc
  11. 4
      selfdrive/ui/sidebar.hpp
  12. 2
      selfdrive/ui/ui.cc
  13. 4
      selfdrive/ui/ui.hpp

@ -27,7 +27,7 @@ qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs)
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=base_libs)
# build main UI
qt_src = ["main.cc", "ui.cc", "paint.cc", "sidebar.cc", "qt/onroad.cc",
qt_src = ["main.cc", "ui.cc", "paint.cc", "qt/sidebar.cc", "qt/onroad.cc",
"qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
"qt/offroad/onboarding.cc", "#phonelibs/nanovg/nanovg.c"]

@ -19,7 +19,6 @@
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"
#include "paint.hpp"
#include "sidebar.hpp"
// TODO: this is also hardcoded in common/transformations/camera.py
// TODO: choose based on frame input size
@ -240,7 +239,6 @@ static void ui_draw_vision_face(UIState *s) {
}
static void ui_draw_driver_view(UIState *s) {
s->sidebar_collapsed = true;
const bool is_rhd = s->scene.is_rhd;
const int width = 4 * s->viz_rect.h / 3;
const Rect rect = {s->viz_rect.centerX() - width / 2, s->viz_rect.y, width, s->viz_rect.h}; // x, y, w, h
@ -377,12 +375,8 @@ static void ui_draw_background(UIState *s) {
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
void ui_draw(UIState *s) {
s->viz_rect = Rect{bdr_s, bdr_s, s->fb_w - 2 * bdr_s, s->fb_h - 2 * bdr_s};
if (!s->sidebar_collapsed) {
s->viz_rect.x += sbr_w;
s->viz_rect.w -= sbr_w;
}
void ui_draw(UIState *s, int w, int h) {
s->viz_rect = Rect{bdr_s, bdr_s, w - 2 * bdr_s, h - 2 * bdr_s};
const bool draw_alerts = s->scene.started;
const bool draw_vision = draw_alerts && s->vipc_client->connected;
@ -398,7 +392,7 @@ void ui_draw(UIState *s) {
// NVG drawing functions - should be no GL inside NVG frame
nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f);
ui_draw_sidebar(s);
if (draw_vision) {
ui_draw_vision(s);
}

@ -2,7 +2,7 @@
#include "ui.hpp"
void ui_draw(UIState *s);
void ui_draw(UIState *s, int w, int h);
void ui_draw_image(const UIState *s, const Rect &r, const char *name, float alpha);
void ui_draw_rect(NVGcontext *vg, const Rect &r, NVGcolor color, int width, float radius = 0);
void ui_fill_rect(NVGcontext *vg, const Rect &r, const NVGpaint &paint, float radius = 0);

@ -15,22 +15,38 @@
// HomeWindow: the container for the offroad and onroad UIs
HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout();
layout->setStackingMode(QStackedLayout::StackAll);
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(0);
sidebar = new Sidebar(this);
layout->addWidget(sidebar);
QObject::connect(this, &HomeWindow::update, sidebar, &Sidebar::update);
QObject::connect(sidebar, &Sidebar::openSettings, this, &HomeWindow::openSettings);
slayout = new QStackedLayout();
layout->addLayout(slayout);
onroad = new OnroadWindow(this);
layout->addWidget(onroad);
slayout->addWidget(onroad);
QObject::connect(this, &HomeWindow::update, onroad, &OnroadWindow::update);
QObject::connect(this, &HomeWindow::displayPowerChanged, onroad, &OnroadWindow::setEnabled);
home = new OffroadHome();
layout->addWidget(home);
slayout->addWidget(home);
QObject::connect(this, &HomeWindow::openSettings, home, &OffroadHome::refresh);
QObject::connect(this, &HomeWindow::offroadTransition, home, &OffroadHome::setVisible);
setLayout(layout);
}
void HomeWindow::offroadTransition(bool offroad) {
if (offroad) {
slayout->setCurrentWidget(home);
} else {
slayout->setCurrentWidget(onroad);
}
sidebar->setVisible(offroad);
}
void HomeWindow::mousePressEvent(QMouseEvent* e) {
// TODO: make a nice driver view widget
if (QUIState::ui_state.scene.driver_view) {
@ -39,23 +55,18 @@ void HomeWindow::mousePressEvent(QMouseEvent* e) {
return;
}
// Settings button click
if (!QUIState::ui_state.sidebar_collapsed && settings_btn.ptInRect(e->x(), e->y())) {
emit openSettings();
}
// Handle sidebar collapsing
if (QUIState::ui_state.scene.started && (e->x() >= QUIState::ui_state.viz_rect.x - bdr_s)) {
QUIState::ui_state.sidebar_collapsed = !QUIState::ui_state.sidebar_collapsed;
if (childAt(e->pos()) == onroad) {
sidebar->setVisible(!sidebar->isVisible());
}
}
// OffroadHome: the offroad home page
OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) {
OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
QVBoxLayout* main_layout = new QVBoxLayout();
main_layout->setContentsMargins(sbr_w + 50, 50, 50, 50);
main_layout->setMargin(50);
// top header
QHBoxLayout* header_layout = new QHBoxLayout();
@ -111,6 +122,9 @@ OffroadHome::OffroadHome(QWidget* parent) : QWidget(parent) {
setLayout(main_layout);
setStyleSheet(R"(
OffroadHome {
background-color: black;
}
* {
color: white;
}

@ -1,16 +1,18 @@
#pragma once
#include <QFrame>
#include <QLabel>
#include <QPushButton>
#include <QStackedLayout>
#include <QTimer>
#include <QWidget>
#include "sidebar.hpp"
#include "onroad.hpp"
#include "ui/ui.hpp"
#include "widgets/offroad_alerts.hpp"
class OffroadHome : public QWidget {
class OffroadHome : public QFrame {
Q_OBJECT
public:
@ -42,14 +44,17 @@ signals:
// forwarded signals
void displayPowerChanged(bool on);
void offroadTransition(bool offroad);
void update(const UIState &s);
public slots:
void offroadTransition(bool offroad);
protected:
void mousePressEvent(QMouseEvent* e) override;
private:
Sidebar *sidebar;
OffroadHome *home;
OnroadWindow *onroad;
QStackedLayout *layout;
QStackedLayout *slayout;
};

@ -39,12 +39,8 @@ void OnroadWindow::update(const UIState &s) {
}
}
void OnroadWindow::resizeGL(int w, int h) {
std::cout << "resize " << w << "x" << h << std::endl;
}
void OnroadWindow::paintGL() {
ui_draw(&QUIState::ui_state);
ui_draw(&QUIState::ui_state, width(), height());
double cur_draw_t = millis_since_boot();
double dt = cur_draw_t - prev_draw_t;

@ -18,7 +18,6 @@ public:
protected:
void paintGL() override;
void initializeGL() override;
void resizeGL(int w, int h) override;
private:
bool enabled;

@ -0,0 +1,177 @@
#include "common/util.h"
#include "sidebar.hpp"
#include "qt_window.hpp"
StatusWidget::StatusWidget(QString label, QString msg, QColor c, QWidget* parent) : QFrame(parent) {
layout.setSpacing(0);
if(msg.length() > 0){
layout.setContentsMargins(50, 24, 16, 24);
status.setAlignment(Qt::AlignLeft | Qt::AlignHCenter);
status.setStyleSheet(R"(font-size: 65px; font-weight: 500;)");
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);
}
update(label, msg, c);
setMinimumHeight(124);
setStyleSheet("background-color: transparent;");
setLayout(&layout);
}
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);
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(QString label, QString msg, QColor c) {
status.setText(label);
substatus.setText(msg);
color = c;
return;
}
SignalWidget::SignalWidget(QString text, int strength, QWidget* parent) : QFrame(parent), _strength(strength) {
layout.setMargin(0);
layout.setSpacing(0);
layout.insertSpacing(0, 45);
label.setText(text);
layout.addWidget(&label, 0, Qt::AlignLeft);
label.setStyleSheet(R"(font-size: 35px; font-weight: 400;)");
setFixedWidth(177);
setLayout(&layout);
}
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 SignalWidget::update(QString text, int strength){
label.setText(text);
_strength = strength;
}
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("--", 0, this);
layout->addWidget(signal, 0, Qt::AlignTop | Qt::AlignHCenter);
temp = new StatusWidget("0°C", "TEMP", QColor(255, 255, 255), this);
layout->addWidget(temp, 0, Qt::AlignTop);
panda = new StatusWidget("NO\nPANDA", "", QColor(201, 34, 49), this);
layout->addWidget(panda, 0, Qt::AlignTop);
connect = new StatusWidget("CONNECT\nOFFLINE", "", QColor(218, 202, 37), 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", temp_severity_map[s.scene.deviceState.getThermalStatus()]);
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";
}
#ifdef QCOM2
else if (s.scene.started) {
panda_color = s.scene.gpsOK ? COLOR_GOOD : COLOR_WARNING;
panda_message = QString("SAT CNT\n%1").arg(s.scene.satelliteCount);
}
#endif
panda->update(panda_message, "", panda_color);
}

@ -0,0 +1,65 @@
#pragma once
#include <QtWidgets>
#include <ui.hpp>
#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(QString text, int strength, QWidget* parent = 0);
void update(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(QString label, QString msg, QColor c, QWidget* parent = 0);
void update(QString label, QString msg, QColor c);
protected:
void paintEvent(QPaintEvent*) override;
private:
QColor color = COLOR_WARNING;
QLabel status;
QLabel substatus;
QVBoxLayout layout;
};
class Sidebar : public QFrame {
Q_OBJECT
public:
explicit Sidebar(QWidget* parent = 0);
signals:
void openSettings();
public slots:
void update(const UIState &s);
private:
SignalWidget *signal;
StatusWidget *temp;
StatusWidget *panda;
StatusWidget *connect;
};

@ -1,143 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <map>
#include "common/util.h"
#include "paint.hpp"
#include "sidebar.hpp"
static void draw_background(UIState *s) {
const NVGcolor color = nvgRGBA(0x39, 0x39, 0x39, 0xff);
ui_fill_rect(s->vg, {0, 0, sbr_w, s->fb_h}, color);
}
static void draw_settings_button(UIState *s) {
ui_draw_image(s, settings_btn, "button_settings", 0.65f);
}
static void draw_home_button(UIState *s) {
ui_draw_image(s, home_btn, "button_home", 1.0f);
}
static void draw_network_strength(UIState *s) {
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()];
ui_draw_image(s, {58, 196, 176, 27}, util::string_format("network_%d", img_idx).c_str(), 1.0f);
}
static void draw_network_type(UIState *s) {
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 int network_x = 50;
const int network_y = 273;
const int network_w = 100;
const char *network_type = network_type_map[s->scene.deviceState.getNetworkType()];
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-regular");
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, network_x, network_y, network_w, network_type ? network_type : "--", NULL);
}
static void draw_metric(UIState *s, const char *label_str, const char *value_str, const int severity, const int y_offset, const char *message_str) {
NVGcolor status_color;
if (severity == 0) {
status_color = COLOR_WHITE;
} else if (severity == 1) {
status_color = COLOR_YELLOW;
} else if (severity > 1) {
status_color = COLOR_RED;
}
const Rect rect = {30, 338 + y_offset, 240, message_str ? strchr(message_str, '\n') ? 124 : 100 : 148};
ui_draw_rect(s->vg, rect, severity > 0 ? COLOR_WHITE : COLOR_WHITE_ALPHA(85), 2, 20.);
nvgBeginPath(s->vg);
nvgRoundedRectVarying(s->vg, rect.x + 6, rect.y + 6, 18, rect.h - 12, 25, 0, 0, 25);
nvgFillColor(s->vg, status_color);
nvgFill(s->vg);
if (!message_str) {
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 78);
nvgFontFace(s->vg, "sans-bold");
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, rect.x + 50, rect.y + 50, rect.w - 60, value_str, NULL);
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-regular");
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, rect.x + 50, rect.y + 50 + 66, rect.w - 60, label_str, NULL);
} else {
nvgFillColor(s->vg, COLOR_WHITE);
nvgFontSize(s->vg, 48);
nvgFontFace(s->vg, "sans-bold");
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgTextBox(s->vg, rect.x + 35, rect.y + (strchr(message_str, '\n') ? 40 : 50), rect.w - 50, message_str, NULL);
}
}
static void draw_temp_metric(UIState *s) {
static std::map<cereal::DeviceState::ThermalStatus, const int> temp_severity_map = {
{cereal::DeviceState::ThermalStatus::GREEN, 0},
{cereal::DeviceState::ThermalStatus::YELLOW, 1},
{cereal::DeviceState::ThermalStatus::RED, 2},
{cereal::DeviceState::ThermalStatus::DANGER, 3}};
std::string temp_val = std::to_string((int)s->scene.deviceState.getAmbientTempC()) + "°C";
draw_metric(s, "TEMP", temp_val.c_str(), temp_severity_map[s->scene.deviceState.getThermalStatus()], 0, NULL);
}
static void draw_panda_metric(UIState *s) {
const int panda_y_offset = 32 + 148;
int panda_severity = 0;
std::string panda_message = "VEHICLE\nONLINE";
if (s->scene.pandaType == cereal::PandaState::PandaType::UNKNOWN) {
panda_severity = 2;
panda_message = "NO\nPANDA";
}
#ifdef QCOM2
else if (s->scene.started) {
panda_severity = s->scene.gpsOK ? 0 : 1;
panda_message = util::string_format("SAT CNT\n%d", s->scene.satelliteCount);
}
#endif
draw_metric(s, NULL, NULL, panda_severity, panda_y_offset, panda_message.c_str());
}
static void draw_connectivity(UIState *s) {
static std::map<NetStatus, std::pair<const char *, int>> connectivity_map = {
{NET_ERROR, {"CONNECT\nERROR", 2}},
{NET_CONNECTED, {"CONNECT\nONLINE", 0}},
{NET_DISCONNECTED, {"CONNECT\nOFFLINE", 1}},
};
auto net_params = connectivity_map[s->scene.athenaStatus];
draw_metric(s, NULL, NULL, net_params.second, 180 + 158, net_params.first);
}
void ui_draw_sidebar(UIState *s) {
if (s->sidebar_collapsed) {
return;
}
draw_background(s);
draw_settings_button(s);
draw_home_button(s);
draw_network_strength(s);
draw_network_type(s);
draw_temp_metric(s);
draw_panda_metric(s);
draw_connectivity(s);
}

@ -1,4 +0,0 @@
#pragma once
#include "ui.hpp"
void ui_draw_sidebar(UIState *s);

@ -314,12 +314,10 @@ static void update_status(UIState *s) {
s->scene.is_rhd = Params().getBool("IsRHD");
s->scene.end_to_end = Params().getBool("EndToEndToggle");
s->sidebar_collapsed = true;
s->scene.alert_size = cereal::ControlsState::AlertSize::NONE;
s->vipc_client = s->scene.driver_view ? s->vipc_client_front : s->vipc_client_rear;
} else {
s->status = STATUS_OFFROAD;
s->sidebar_collapsed = false;
s->sound->stop();
s->vipc_client->connected = false;
}

@ -44,12 +44,9 @@ typedef struct Rect {
}
} Rect;
const int sbr_w = 300;
const int bdr_s = 30;
const int header_h = 420;
const int footer_h = 280;
const Rect settings_btn = {50, 35, 200, 117};
const Rect home_btn = {60, 1080 - 180 - 40, 180, 180};
const int UI_FREQ = 20; // Hz
@ -157,7 +154,6 @@ typedef struct UIState {
bool awake;
bool sidebar_collapsed;
Rect video_rect, viz_rect;
float car_space_transform[6];
bool wide_camera;

Loading…
Cancel
Save