diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 1ea4d44dc4..da652f7bfd 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -31,7 +31,7 @@ qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc", "qt/offroad/software_settings.cc", "qt/offroad/onboarding.cc", "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", - "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc"] + "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"] # build translation files with open(File("translations/languages.json").abspath) as f: diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index c528501cbe..fd8ad19c2e 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -6,7 +6,6 @@ #include #include "common/swaglog.h" -#include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/util.h" // Window that shows camera view and variety of info drawn on top @@ -23,98 +22,11 @@ AnnotatedCameraWidget::AnnotatedCameraWidget(VisionStreamType type, QWidget *par } void AnnotatedCameraWidget::updateState(const UIState &s) { - const int SET_SPEED_NA = 255; - const SubMaster &sm = *(s.sm); - - const bool cs_alive = sm.alive("carState"); - const auto cs = sm["controlsState"].getControlsState(); - const auto car_state = sm["carState"].getCarState(); - - is_metric = s.scene.is_metric; - - // Handle older routes where vCruise was in controlsState - float v_cruise = car_state.getVCruiseCluster() == 0.0 ? cs.getVCruiseDEPRECATED() : car_state.getVCruiseCluster(); - setSpeed = cs_alive ? v_cruise : SET_SPEED_NA; - is_cruise_set = setSpeed > 0 && (int)setSpeed != SET_SPEED_NA; - if (is_cruise_set && !is_metric) { - setSpeed *= KM_TO_MILE; - } - - // Handle older routes where vEgoCluster is not set - v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; - float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); - speed = cs_alive ? std::max(0.0, v_ego) : 0.0; - speed *= is_metric ? MS_TO_KPH : MS_TO_MPH; - - speedUnit = is_metric ? tr("km/h") : tr("mph"); - status = s.status; - // update engageability/experimental mode button experimental_btn->updateState(s); - - // update DM icon dmon.updateState(s); } -void AnnotatedCameraWidget::drawHud(QPainter &p) { - p.save(); - - // Header gradient - QLinearGradient bg(0, UI_HEADER_HEIGHT - (UI_HEADER_HEIGHT / 2.5), 0, UI_HEADER_HEIGHT); - bg.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.45)); - bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); - p.fillRect(0, 0, width(), UI_HEADER_HEIGHT, bg); - - QString speedStr = QString::number(std::nearbyint(speed)); - QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(setSpeed)) : "–"; - - // Draw outer box + border to contain set speed - const QSize default_size = {172, 204}; - QSize set_speed_size = default_size; - if (is_metric) set_speed_size.rwidth() = 200; - - QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); - p.setPen(QPen(whiteColor(75), 6)); - p.setBrush(blackColor(166)); - p.drawRoundedRect(set_speed_rect, 32, 32); - - // Draw MAX - QColor max_color = QColor(0x80, 0xd8, 0xa6, 0xff); - QColor set_speed_color = whiteColor(); - if (is_cruise_set) { - if (status == STATUS_DISENGAGED) { - max_color = whiteColor(); - } else if (status == STATUS_OVERRIDE) { - max_color = QColor(0x91, 0x9b, 0x95, 0xff); - } - } else { - max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); - set_speed_color = QColor(0x72, 0x72, 0x72, 0xff); - } - p.setFont(InterFont(40, QFont::DemiBold)); - p.setPen(max_color); - p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX")); - p.setFont(InterFont(90, QFont::Bold)); - p.setPen(set_speed_color); - p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); - - // current speed - p.setFont(InterFont(176, QFont::Bold)); - drawText(p, rect().center().x(), 210, speedStr); - p.setFont(InterFont(66)); - drawText(p, rect().center().x(), 290, speedUnit, 200); - - p.restore(); -} - -void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { - QRect real_rect = p.fontMetrics().boundingRect(text); - real_rect.moveCenter({x, y - real_rect.height() / 2}); - - p.setPen(QColor(0xff, 0xff, 0xff, alpha)); - p.drawText(real_rect.x(), real_rect.bottom(), text); -} - void AnnotatedCameraWidget::initializeGL() { CameraWidget::initializeGL(); qInfo() << "OpenGL version:" << QString((const char*)glGetString(GL_VERSION)); @@ -333,8 +245,8 @@ void AnnotatedCameraWidget::paintGL() { } dmon.draw(painter, rect()); - - drawHud(painter); + hud.updateState(*s); + hud.draw(painter, rect()); double cur_draw_t = millis_since_boot(); double dt = cur_draw_t - prev_draw_t; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index 3820de5d86..324a6d7458 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -2,7 +2,7 @@ #include #include - +#include "selfdrive/ui/qt/onroad/hud.h" #include "selfdrive/ui/qt/onroad/buttons.h" #include "selfdrive/ui/qt/onroad/driver_monitoring.h" #include "selfdrive/ui/qt/widgets/cameraview.h" @@ -15,18 +15,10 @@ public: void updateState(const UIState &s); private: - void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); - QVBoxLayout *main_layout; ExperimentalButton *experimental_btn; DriverMonitorRenderer dmon; - float speed; - QString speedUnit; - float setSpeed; - bool is_cruise_set = false; - bool is_metric = false; - bool v_ego_cluster_seen = false; - int status = STATUS_DISENGAGED; + HudRenderer hud; std::unique_ptr pm; int skip_frame_count = 0; @@ -39,10 +31,7 @@ protected: mat4 calcFrameMatrix() override; void drawLaneLines(QPainter &painter, const UIState *s); void drawLead(QPainter &painter, const cereal::RadarState::LeadData::Reader &lead_data, const QPointF &vd); - void drawHud(QPainter &p); inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); } - inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); } - inline QColor blackColor(int alpha = 255) { return QColor(0, 0, 0, alpha); } double prev_draw_t = 0; FirstOrderFilter fps_filter; diff --git a/selfdrive/ui/qt/onroad/hud.cc b/selfdrive/ui/qt/onroad/hud.cc new file mode 100644 index 0000000000..ebd95dab43 --- /dev/null +++ b/selfdrive/ui/qt/onroad/hud.cc @@ -0,0 +1,109 @@ +#include "selfdrive/ui/qt/onroad/hud.h" + +#include + +#include "selfdrive/ui/qt/util.h" + +constexpr int SET_SPEED_NA = 255; + +HudRenderer::HudRenderer() {} + +void HudRenderer::updateState(const UIState &s) { + is_metric = s.scene.is_metric; + status = s.status; + + const SubMaster &sm = *(s.sm); + if (!sm.alive("carState")) { + is_cruise_set = false; + set_speed = SET_SPEED_NA; + speed = 0.0; + return; + } + + const auto &controls_state = sm["controlsState"].getControlsState(); + const auto &car_state = sm["carState"].getCarState(); + + // Handle older routes where vCruiseCluster is not set + set_speed = car_state.getVCruiseCluster() == 0.0 ? controls_state.getVCruiseDEPRECATED() : car_state.getVCruiseCluster(); + is_cruise_set = set_speed > 0 && set_speed != SET_SPEED_NA; + + if (is_cruise_set && !is_metric) { + set_speed *= KM_TO_MILE; + } + + // Handle older routes where vEgoCluster is not set + v_ego_cluster_seen = v_ego_cluster_seen || car_state.getVEgoCluster() != 0.0; + float v_ego = v_ego_cluster_seen ? car_state.getVEgoCluster() : car_state.getVEgo(); + speed = std::max(0.0f, v_ego * (is_metric ? MS_TO_KPH : MS_TO_MPH)); +} + +void HudRenderer::draw(QPainter &p, const QRect &surface_rect) { + p.save(); + + // Draw header gradient + QLinearGradient bg(0, UI_HEADER_HEIGHT - (UI_HEADER_HEIGHT / 2.5), 0, UI_HEADER_HEIGHT); + bg.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0.45)); + bg.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); + p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg); + + + drawSetSpeed(p, surface_rect); + drawCurrentSpeed(p, surface_rect); + + p.restore(); +} + +void HudRenderer::drawSetSpeed(QPainter &p, const QRect &surface_rect) { + // Draw outer box + border to contain set speed + const QSize default_size = {172, 204}; + QSize set_speed_size = is_metric ? QSize(200, 204) : default_size; + QRect set_speed_rect(QPoint(60 + (default_size.width() - set_speed_size.width()) / 2, 45), set_speed_size); + + // Draw set speed box + p.setPen(QPen(QColor(255, 255, 255, 75), 6)); + p.setBrush(QColor(0, 0, 0, 166)); + p.drawRoundedRect(set_speed_rect, 32, 32); + + // Colors based on status + QColor max_color = QColor(0xa6, 0xa6, 0xa6, 0xff); + QColor set_speed_color = QColor(0x72, 0x72, 0x72, 0xff); + if (is_cruise_set) { + if (status == STATUS_DISENGAGED) { + max_color = QColor(255, 255, 255); + } else if (status == STATUS_OVERRIDE) { + max_color = QColor(0x91, 0x9b, 0x95, 0xff); + } else { + max_color = QColor(0x80, 0xd8, 0xa6, 0xff); + set_speed_color = QColor(255, 255, 255); + } + } + + // Draw "MAX" text + p.setFont(InterFont(40, QFont::DemiBold)); + p.setPen(max_color); + p.drawText(set_speed_rect.adjusted(0, 27, 0, 0), Qt::AlignTop | Qt::AlignHCenter, tr("MAX")); + + // Draw set speed + QString setSpeedStr = is_cruise_set ? QString::number(std::nearbyint(set_speed)) : "–"; + p.setFont(InterFont(90, QFont::Bold)); + p.setPen(set_speed_color); + p.drawText(set_speed_rect.adjusted(0, 77, 0, 0), Qt::AlignTop | Qt::AlignHCenter, setSpeedStr); +} + +void HudRenderer::drawCurrentSpeed(QPainter &p, const QRect &surface_rect) { + QString speedStr = QString::number(std::nearbyint(speed)); + + p.setFont(InterFont(176, QFont::Bold)); + drawText(p, surface_rect.center().x(), 210, speedStr); + + p.setFont(InterFont(66)); + drawText(p, surface_rect.center().x(), 290, is_metric ? tr("km/h") : tr("mph"), 200); +} + +void HudRenderer::drawText(QPainter &p, int x, int y, const QString &text, int alpha) { + QRect real_rect = p.fontMetrics().boundingRect(text); + real_rect.moveCenter({x, y - real_rect.height() / 2}); + + p.setPen(QColor(0xff, 0xff, 0xff, alpha)); + p.drawText(real_rect.x(), real_rect.bottom(), text); +} diff --git a/selfdrive/ui/qt/onroad/hud.h b/selfdrive/ui/qt/onroad/hud.h new file mode 100644 index 0000000000..9151b23a4d --- /dev/null +++ b/selfdrive/ui/qt/onroad/hud.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "selfdrive/ui/ui.h" + +class HudRenderer : public QObject { +public: + HudRenderer(); + void updateState(const UIState &s); + void draw(QPainter &p, const QRect &surface_rect); + +private: + void drawSetSpeed(QPainter &p, const QRect &surface_rect); + void drawCurrentSpeed(QPainter &p, const QRect &surface_rect); + void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); + + float speed = 0; + float set_speed = 0; + bool is_cruise_set = false; + bool is_metric = false; + bool v_ego_cluster_seen = false; + int status = STATUS_DISENGAGED; +}; diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index d73a5771fd..5f254e9cd4 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -87,21 +87,6 @@ من أجل "%1" - - AnnotatedCameraWidget - - km/h - كم/س - - - mph - ميل/س - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ تشغيل وضع الراحة + + HudRenderer + + km/h + كم/س + + + mph + ميل/س + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index 8ad55be666..4f5997228a 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -87,21 +87,6 @@ für "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ ENTSPANNTER MODUS AN + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index 510a2d98e0..fa50f33f15 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -87,21 +87,6 @@ para "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ MODO CHILL + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 80cca809e0..566ed32f11 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -87,21 +87,6 @@ pour "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mi/h - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ MODE DÉTENTE ACTIVÉ + + HudRenderer + + km/h + km/h + + + mph + mi/h + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index 2b8f7d2429..90c8aba00b 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -87,21 +87,6 @@ ネットワーク名:%1 - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - 最高速度 - - ConfirmationDialog @@ -289,6 +274,21 @@ チルモード + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + 最高速度 + + InputDialog diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 935342d546..6d01b1289f 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -87,21 +87,6 @@ "%1"에 접속하려면 비밀번호가 필요합니다 - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ 안정 모드 사용 + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 1c1ebff15b..ba50e97141 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -87,21 +87,6 @@ para "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - LIMITE - - ConfirmationDialog @@ -289,6 +274,21 @@ MODO CHILL ON + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + LIMITE + + InputDialog diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index 06841222cc..6d89c049b1 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -87,21 +87,6 @@ สำหรับ "%1" - - AnnotatedCameraWidget - - km/h - กม./ชม. - - - mph - ไมล์/ชม. - - - MAX - สูงสุด - - ConfirmationDialog @@ -289,6 +274,21 @@ คุณกำลังใช้โหมดชิล + + HudRenderer + + km/h + กม./ชม. + + + mph + ไมล์/ชม. + + + MAX + สูงสุด + + InputDialog diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index f934b9d9cc..663ad8c281 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -87,21 +87,6 @@ için "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - MAX - - ConfirmationDialog @@ -289,6 +274,21 @@ + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + MAX + + InputDialog diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index d900202515..494b1bc170 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -87,21 +87,6 @@ 网络名称:"%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - 最高定速 - - ConfirmationDialog @@ -289,6 +274,21 @@ 轻松模式运行 + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + 最高定速 + + InputDialog diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index 91b1cf3866..7ce6ac6d20 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -87,21 +87,6 @@ 給 "%1" - - AnnotatedCameraWidget - - km/h - km/h - - - mph - mph - - - MAX - 最高 - - ConfirmationDialog @@ -289,6 +274,21 @@ 輕鬆模式 ON + + HudRenderer + + km/h + km/h + + + mph + mph + + + MAX + 最高 + + InputDialog