mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-03-01 08:13:52 +08:00
221 lines
9.2 KiB
C++
221 lines
9.2 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <map>
|
|
|
|
#include "paint.hpp"
|
|
#include "sidebar.hpp"
|
|
|
|
static void ui_draw_sidebar_background(UIState *s) {
|
|
int sbr_x = !s->scene.uilayout_sidebarcollapsed ? 0 : -(sbr_w) + bdr_s * 2;
|
|
ui_draw_rect(s->vg, sbr_x, 0, sbr_w, s->fb_h, COLOR_BLACK_ALPHA(85));
|
|
}
|
|
|
|
static void ui_draw_sidebar_settings_button(UIState *s) {
|
|
const float alpha = s->active_app == cereal::UiLayoutState::App::SETTINGS ? 1.0f : 0.65f;
|
|
ui_draw_image(s->vg, settings_btn.x, settings_btn.y, settings_btn.w, settings_btn.h, s->img_button_settings, alpha);
|
|
}
|
|
|
|
static void ui_draw_sidebar_home_button(UIState *s) {
|
|
const float alpha = s->active_app == cereal::UiLayoutState::App::HOME ? 1.0f : 0.65f;;
|
|
ui_draw_image(s->vg, home_btn.x, home_btn.y, home_btn.w, home_btn.h, s->img_button_home, alpha);
|
|
if (s->scene.dpIsUpdating) {
|
|
nvgBeginPath(s->vg);
|
|
nvgCircle(s->vg, home_btn.x + home_btn.w/2, home_btn.y + home_btn.h/2, 90);
|
|
nvgFillColor(s->vg, nvgRGBA(255, 255, 255, s->scene.dp_alert_rate));
|
|
nvgFill(s->vg);
|
|
|
|
nvgFillColor(s->vg, nvgRGBA(0, 0, 0, s->scene.dp_alert_rate));
|
|
nvgFontSize(s->vg, s->scene.dpLocale == "zh-TW"? 60 : s->scene.dpLocale == "zh-CN"? 60 : 46);
|
|
nvgFontFaceId(s->vg, s->font_sans_bold);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, home_btn.x, home_btn.y + home_btn.h/2, home_btn.w,
|
|
s->scene.dpLocale == "zh-TW"? "更新中" : s->scene.dpLocale == "zh-CN"? "更新中" : "UPDATING",
|
|
NULL);
|
|
|
|
s->scene.dp_alert_rate += 5*s->scene.dp_alert_type;
|
|
|
|
if (s->scene.dp_alert_rate <= 0 || s->scene.dp_alert_rate >= 255) {
|
|
s->scene.dp_alert_type *= -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ui_draw_sidebar_network_strength(UIState *s) {
|
|
static std::map<cereal::ThermalData::NetworkStrength, int> network_strength_map = {
|
|
{cereal::ThermalData::NetworkStrength::UNKNOWN, 1},
|
|
{cereal::ThermalData::NetworkStrength::POOR, 2},
|
|
{cereal::ThermalData::NetworkStrength::MODERATE, 3},
|
|
{cereal::ThermalData::NetworkStrength::GOOD, 4},
|
|
{cereal::ThermalData::NetworkStrength::GREAT, 5}};
|
|
const int network_img_h = 27;
|
|
const int network_img_w = 176;
|
|
const int network_img_x = 58;
|
|
const int network_img_y = 196;
|
|
const int img_idx = s->scene.thermal.getNetworkType() == cereal::ThermalData::NetworkType::NONE ? 0 : network_strength_map[s->scene.thermal.getNetworkStrength()];
|
|
ui_draw_image(s->vg, network_img_x, network_img_y, network_img_w, network_img_h, s->img_network[img_idx], 1.0f);
|
|
}
|
|
|
|
static void ui_draw_sidebar_ip_addr(UIState *s) {
|
|
const int network_ip_w = 176;
|
|
const int network_ip_x = 54;
|
|
const int network_ip_y = 255;
|
|
nvgFillColor(s->vg, COLOR_WHITE);
|
|
nvgFontSize(s->vg, 34);
|
|
nvgFontFaceId(s->vg, s->font_sans_regular);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, network_ip_x, network_ip_y, network_ip_w, s->scene.dpIpAddr.c_str(), NULL);
|
|
}
|
|
|
|
static void ui_draw_sidebar_battery_text(UIState *s) {
|
|
const int battery_txt_w = 96;
|
|
const int battery_txt_x = 160;
|
|
const int battery_txt_y = 305;
|
|
char battery_str[7];
|
|
snprintf(battery_str, sizeof(battery_str), "%d%%%s", s->scene.thermal.getBatteryPercent(), s->scene.thermal.getBatteryStatus() == "Charging" ? "+" : "-");
|
|
nvgFillColor(s->vg, COLOR_WHITE);
|
|
nvgFontSize(s->vg, 44);
|
|
nvgFontFaceId(s->vg, s->font_sans_regular);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, battery_txt_x, battery_txt_y, battery_txt_w, battery_str, NULL);
|
|
}
|
|
|
|
//static void ui_draw_sidebar_battery_icon(UIState *s) {
|
|
// const int battery_img_h = 36;
|
|
// const int battery_img_w = 76;
|
|
// const int battery_img_x = 160;
|
|
// const int battery_img_y = 255;
|
|
//
|
|
// int battery_img = s->scene.thermal.getBatteryStatus() == "Charging" ? s->img_battery_charging : s->img_battery;
|
|
//
|
|
// ui_draw_rect(s->vg, battery_img_x + 6, battery_img_y + 5,
|
|
// ((battery_img_w - 19) * (s->scene.thermal.getBatteryPercent() * 0.01)), battery_img_h - 11, COLOR_WHITE);
|
|
//
|
|
// ui_draw_image(s->vg, battery_img_x, battery_img_y, battery_img_w, battery_img_h, battery_img, 1.0f);
|
|
//}
|
|
|
|
static void ui_draw_sidebar_network_type(UIState *s) {
|
|
static std::map<cereal::ThermalData::NetworkType, const char *> network_type_map = {
|
|
{cereal::ThermalData::NetworkType::NONE, "--"},
|
|
{cereal::ThermalData::NetworkType::WIFI, "WiFi"},
|
|
{cereal::ThermalData::NetworkType::CELL2_G, "2G"},
|
|
{cereal::ThermalData::NetworkType::CELL3_G, "3G"},
|
|
{cereal::ThermalData::NetworkType::CELL4_G, "4G"},
|
|
{cereal::ThermalData::NetworkType::CELL5_G, "5G"}};
|
|
const int network_x = 50;
|
|
const int network_y = 303;
|
|
const int network_w = 100;
|
|
const char *network_type = network_type_map[s->scene.thermal.getNetworkType()];
|
|
nvgFillColor(s->vg, COLOR_WHITE);
|
|
nvgFontSize(s->vg, 48);
|
|
nvgFontFaceId(s->vg, s->font_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 ui_draw_sidebar_metric(UIState *s, const char* label_str, const char* value_str, const int severity, const int y_offset, const char* message_str) {
|
|
const int metric_x = 30;
|
|
const int metric_y = 338 + y_offset;
|
|
const int metric_w = 240;
|
|
const int metric_h = message_str ? strchr(message_str, '\n') ? 124 : 100 : 148;
|
|
|
|
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;
|
|
}
|
|
|
|
ui_draw_rect(s->vg, metric_x, metric_y, metric_w, metric_h,
|
|
severity > 0 ? COLOR_WHITE : COLOR_WHITE_ALPHA(85), 20, 2);
|
|
|
|
nvgBeginPath(s->vg);
|
|
nvgRoundedRectVarying(s->vg, metric_x + 6, metric_y + 6, 18, metric_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);
|
|
nvgFontFaceId(s->vg, s->font_sans_bold);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, metric_x + 50, metric_y + 50, metric_w - 60, value_str, NULL);
|
|
|
|
nvgFillColor(s->vg, COLOR_WHITE);
|
|
nvgFontSize(s->vg, 46);
|
|
nvgFontFaceId(s->vg, s->font_sans_regular);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, metric_x + 50, metric_y + 50 + 66, metric_w - 60, label_str, NULL);
|
|
} else {
|
|
nvgFillColor(s->vg, COLOR_WHITE);
|
|
nvgFontSize(s->vg, 46);
|
|
nvgFontFaceId(s->vg, s->font_sans_bold);
|
|
nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
nvgTextBox(s->vg, metric_x + 35, metric_y + (strchr(message_str, '\n') ? 40 : 50), metric_w - 50, message_str, NULL);
|
|
}
|
|
}
|
|
|
|
static void ui_draw_sidebar_temp_metric(UIState *s) {
|
|
static std::map<cereal::ThermalData::ThermalStatus, const int> temp_severity_map = {
|
|
{cereal::ThermalData::ThermalStatus::GREEN, 0},
|
|
{cereal::ThermalData::ThermalStatus::YELLOW, 1},
|
|
{cereal::ThermalData::ThermalStatus::RED, 2},
|
|
{cereal::ThermalData::ThermalStatus::DANGER, 3}};
|
|
std::string temp_val = std::to_string((int)s->scene.thermal.getAmbient()) + "°C";
|
|
std::string temp_label = s->scene.dpLocale == "zh-TW"? "溫度" : s->scene.dpLocale == "zh-CN"? "温度" : "TEMP";
|
|
ui_draw_sidebar_metric(s, temp_label.c_str(), temp_val.c_str(), temp_severity_map[s->scene.thermal.getThermalStatus()], 0, NULL);
|
|
}
|
|
|
|
static void ui_draw_sidebar_panda_metric(UIState *s) {
|
|
const int panda_y_offset = 32 + 148;
|
|
|
|
int panda_severity = 0;
|
|
std::string car = s->scene.dpLocale == "zh-TW"? "車輛" : s->scene.dpLocale == "zh-CN"? "车辆" : "VEHICLE";
|
|
std::string panda_message = car + (s->scene.dpLocale == "zh-TW"? "\n已連線" : s->scene.dpLocale == "zh-CN"? "\n在线" : "\nONLINE");
|
|
if (s->scene.hwType == cereal::HealthData::HwType::UNKNOWN) {
|
|
panda_severity = 2;
|
|
panda_message = car + (s->scene.dpLocale == "zh-TW"? "\n已離線" : s->scene.dpLocale == "zh-CN"? "\n离线" : "\nOFFLINE");
|
|
} else if (s->started) {
|
|
if (s->scene.satelliteCount < 6) {
|
|
panda_severity = 1;
|
|
panda_message = car + "\nGPS: " + std::to_string(s->scene.satelliteCount);
|
|
} else {
|
|
panda_severity = 0;
|
|
panda_message = car + "\nGPS: " + std::to_string(s->scene.satelliteCount);
|
|
}
|
|
}
|
|
ui_draw_sidebar_metric(s, NULL, NULL, panda_severity, panda_y_offset, panda_message.c_str());
|
|
}
|
|
|
|
static void ui_draw_sidebar_connectivity(UIState *s) {
|
|
if (s->scene.dpAthenad) {
|
|
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];
|
|
ui_draw_sidebar_metric(s, NULL, NULL, net_params.second, 180+158, net_params.first);
|
|
}
|
|
}
|
|
|
|
void ui_draw_sidebar(UIState *s) {
|
|
ui_draw_sidebar_background(s);
|
|
if (s->scene.uilayout_sidebarcollapsed) {
|
|
return;
|
|
}
|
|
ui_draw_sidebar_settings_button(s);
|
|
ui_draw_sidebar_home_button(s);
|
|
ui_draw_sidebar_network_strength(s);
|
|
// ui_draw_sidebar_battery_icon(s);
|
|
ui_draw_sidebar_ip_addr(s);
|
|
ui_draw_sidebar_battery_text(s);
|
|
ui_draw_sidebar_network_type(s);
|
|
ui_draw_sidebar_temp_metric(s);
|
|
ui_draw_sidebar_panda_metric(s);
|
|
ui_draw_sidebar_connectivity(s);
|
|
}
|