diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 74cf1a38b..eec2bd5a6 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -225,20 +225,56 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) { // current speed if (!(bigMapOpen || hideSpeed)) { - 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); + if (standstillDuration != 0) { + float transition = qBound(0.0f, standstillDuration / 120.0f, 1.0f); + QColor start, end; + + if (standstillDuration <= 60) { + start = end = bg_colors[STATUS_ENGAGED]; + } else if (standstillDuration <= 90) { + start = bg_colors[STATUS_ENGAGED]; + end = bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]; + transition = (standstillDuration - 60) / 30.0f; + } else if (standstillDuration <= 120) { + start = bg_colors[STATUS_CONDITIONAL_OVERRIDDEN]; + end = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; + transition = (standstillDuration - 90) / 30.0f; + } else { + start = end = bg_colors[STATUS_TRAFFIC_MODE_ACTIVE]; + transition = 0.0f; + } + + float red = start.redF() + transition * (end.redF() - start.redF()); + float green = start.greenF() + transition * (end.greenF() - start.greenF()); + float blue = start.blueF() + transition * (end.blueF() - start.blueF()); + + p.setPen(QPen(QColor::fromRgbF(red, green, blue))); + + int minutes = standstillDuration / 60; + int seconds = standstillDuration % 60; + + p.setFont(InterFont(176, QFont::Bold)); + drawText(p, rect().center().x(), 210, minutes == 1 ? "1 minute" : QString("%1 minutes").arg(minutes), 255, true); + p.setFont(InterFont(66)); + drawText(p, rect().center().x(), 290, QString("%1 seconds").arg(seconds)); + } else { + 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) { +void AnnotatedCameraWidget::drawText(QPainter &p, int x, int y, const QString &text, int alpha, bool overridePen) { QRect real_rect = p.fontMetrics().boundingRect(text); real_rect.moveCenter({x, y - real_rect.height() / 2}); - p.setPen(QColor(0xff, 0xff, 0xff, alpha)); + if (!overridePen) { + p.setPen(QColor(0xff, 0xff, 0xff, alpha)); + } p.drawText(real_rect.x(), real_rect.bottom(), text); } @@ -893,6 +929,17 @@ void AnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &painter, const UISce drawSLCConfirmation(painter); } + bool stoppedTimer = scene.stopped_timer && scene.standstill && scene.started_timer / UI_FREQ >= 10; + if (stoppedTimer) { + if (!standstillTimer.isValid()) { + standstillTimer.start(); + } + standstillDuration = standstillTimer.elapsed() / 1000.0; + } else { + standstillDuration = 0; + standstillTimer.invalidate(); + } + trafficModeActive = scene.traffic_mode_active; turnSignalLeft = scene.turn_signal_left; diff --git a/selfdrive/ui/qt/onroad/annotated_camera.h b/selfdrive/ui/qt/onroad/annotated_camera.h index f74290721..50a0400a7 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.h +++ b/selfdrive/ui/qt/onroad/annotated_camera.h @@ -63,7 +63,7 @@ public: MapSettingsButton *map_settings_btn_bottom; private: - void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255); + void drawText(QPainter &p, int x, int y, const QString &text, int alpha = 255, bool overridePen = false); QVBoxLayout *main_layout; ExperimentalButton *experimental_btn; @@ -154,6 +154,7 @@ private: int desiredFollow; int obstacleDistance; int obstacleDistanceStock; + int standstillDuration; int stoppedEquivalence; int totalFrames; @@ -170,6 +171,7 @@ private: std::vector signalImgVector; + QElapsedTimer standstillTimer; QTimer *animationTimer; inline QColor blueColor(int alpha = 255) { return QColor(0, 150, 255, alpha); } diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index eef9f939e..582ad6d4a 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -425,6 +425,7 @@ void ui_update_frogpilot_params(UIState *s, Params ¶ms) { scene.hide_speed = quality_of_life_visuals && params.getBool("HideSpeed"); scene.hide_speed_ui = scene.hide_speed && params.getBool("HideSpeedUI"); scene.map_style = quality_of_life_visuals ? params.getInt("MapStyle") : 0; + scene.stopped_timer = quality_of_life_visuals && params.getBool("StoppedTimer"); scene.speed_limit_controller = scene.longitudinal_control && params.getBool("SpeedLimitController"); scene.show_slc_offset = scene.speed_limit_controller && params.getBool("ShowSLCOffset"); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 25ca589dc..3c4f94d27 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -191,6 +191,7 @@ typedef struct UIScene { bool speed_limit_overridden; bool standstill; bool static_pedals_on_ui; + bool stopped_timer; bool tethering_enabled; bool traffic_mode; bool traffic_mode_active; @@ -243,6 +244,7 @@ typedef struct UIScene { int model_length; int obstacle_distance; int obstacle_distance_stock; + int started_timer; int steering_angle_deg; int stopped_equivalence; int tethering_config;