diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index 4d651ce37f..d1b04a0d50 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -81,14 +81,24 @@ void HomeWindow::showDriverView(bool show) { } void HomeWindow::mousePressEvent(QMouseEvent* e) { - // Handle sidebar collapsing - if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) { - sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible()); + if (uiState()->scene.started) { + if (uiState()->scene.onroadScreenOff != -2) { + uiState()->scene.touched2 = true; + QTimer::singleShot(500, []() { uiState()->scene.touched2 = false; }); + } + if (uiState()->scene.button_auto_hide) { + uiState()->scene.touch_to_wake = true; + uiState()->scene.sleep_btn_fading_in = true; + QTimer::singleShot(500, []() { uiState()->scene.touch_to_wake = false; }); + } } - if (uiState()->scene.started && uiState()->scene.onroadScreenOff != -2) { - uiState()->scene.touched2 = true; - QTimer::singleShot(500, []() { uiState()->scene.touched2 = false; }); + // Handle sidebar collapsing + if ((onroad->isVisible() || body->isVisible()) && (!sidebar->isVisible() || e->x() > sidebar->width())) { + if ((uiState()->scene.sleep_btn != 0 && uiState()->scene.sleep_btn_opacity != 0) || + (uiState()->scene.sleep_time != 0 && uiState()->scene.onroadScreenOff != -2)) { + sidebar->setVisible(!sidebar->isVisible() && !onroad->isMapVisible()); + } } } diff --git a/selfdrive/ui/qt/offroad/sunnypilot_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot_settings.cc index 0f553d62cd..e82971f9b0 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot_settings.cc @@ -594,6 +594,16 @@ SPVisualsPanel::SPVisualsPanel(QWidget *parent) : QWidget(parent) { main_layout->addWidget(devUiMain); + // Visuals: Auto-Hide UI Button + main_layout->addWidget(horizontal_line()); + main_layout->addWidget(new ParamControl( + "ButtonAutoHide", + tr("Auto-Hide UI Buttons"), + tr("Hide UI buttons on driving screen after a 30-second timeout. Tap on the screen at anytime to reveal the UI buttons."), + "../assets/offroad/icon_road.png" + )); + + // Visuals: OSM: Show debug UI elements main_layout->addWidget(horizontal_line()); main_layout->addWidget(new ParamControl( diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index 69a979b944..0032cf5d30 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -160,13 +160,13 @@ void OnroadWindow::mousePressEvent(QMouseEvent* e) { QRect debug_tap_rect = QRect(rect().center().x() - 200, rect().center().y() - 200, 400, 400); QRect speed_limit_touch_rect = speed_sgn_rc.adjusted(-50, -50, 50, 50); - if (scene.dynamic_lane_profile_toggle && dlp_btn_rect.contains(e->x(), e->y())) { + if (scene.dynamic_lane_profile_toggle && scene.sleep_btn_opacity == 20 && dlp_btn_rect.contains(e->x(), e->y())) { scene.dynamic_lane_profile++; scene.dynamic_lane_profile = scene.dynamic_lane_profile > 2 ? 0 : scene.dynamic_lane_profile; params.put("DynamicLaneProfile", std::to_string(scene.dynamic_lane_profile)); propagate_event = false; } else if (scene.gac && scene.gac_mode != 0 && scene.longitudinal_control && !controls_state.getExperimentalMode() && - car_state.getCruiseState().getAvailable() && gac_btn_rect.contains(e->x(), e->y())) { + car_state.getCruiseState().getAvailable() && scene.sleep_btn_opacity == 20 && gac_btn_rect.contains(e->x(), e->y())) { scene.gac_tr--; scene.gac_tr = scene.gac_tr < scene.gac_min ? scene.gac_max : scene.gac_tr; params.put("GapAdjustCruiseTr", std::to_string(scene.gac_tr)); @@ -470,6 +470,8 @@ void AnnotatedCameraWidget::updateState(const UIState &s) { setProperty("liveValid", ltp.getLiveValid()); // ############################## DEV UI END ############################## + setProperty("btnPerc", s.scene.sleep_btn_opacity * 0.05); + // update engageability/experimental mode button experimental_btn->updateState(s); @@ -855,27 +857,27 @@ void AnnotatedCameraWidget::drawVisionTurnControllerUI(QPainter &p, int x, int y void AnnotatedCameraWidget::drawDlpButton(QPainter &p, int x, int y, int w, int h) { int prev_dynamic_lane_profile = -1; QString dlp_text = ""; - QColor dlp_border = QColor(255, 255, 255, 255); + QColor dlp_border = QColor(255, 255, 255, (255 * btnPerc)); if (prev_dynamic_lane_profile != dynamicLaneProfile) { prev_dynamic_lane_profile = dynamicLaneProfile; if (dynamicLaneProfile == 0) { dlp_text = tr("Lane\nonly"); - dlp_border = QColor("#2020f8"); + dlp_border = QColor(32, 32, 248, (255 * btnPerc)); } else if (dynamicLaneProfile == 1) { dlp_text = tr("Lane\nless"); - dlp_border = QColor("#0df87a"); + dlp_border = QColor(13, 248, 122, (255 * btnPerc)); } else if (dynamicLaneProfile == 2) { dlp_text = tr("Auto\nLane"); - dlp_border = QColor("#0df8f8"); + dlp_border = QColor(13, 248, 248, (255 * btnPerc)); } } QRect dlpBtn(x, y, w, h); p.setPen(QPen(dlp_border, 6)); - p.setBrush(QColor(75, 75, 75, 75)); + p.setBrush(QColor(75, 75, 75, (75 * btnPerc))); p.drawEllipse(dlpBtn); - p.setPen(QColor(Qt::white)); + p.setPen(QColor(255, 255, 255, (255 * btnPerc))); configFont(p, "Inter", 36, "SemiBold"); p.drawText(dlpBtn, Qt::AlignCenter, dlp_text); } @@ -883,27 +885,27 @@ void AnnotatedCameraWidget::drawDlpButton(QPainter &p, int x, int y, int w, int void AnnotatedCameraWidget::drawGacButton(QPainter &p, int x, int y, int w, int h) { int prev_gac_tr = -1; QString gac_text = ""; - QColor gac_border = QColor(255, 255, 255, 255); + QColor gac_border = QColor(255, 255, 255, (255 * btnPerc)); if (prev_gac_tr != gacTr) { prev_gac_tr = gacTr; if (gacTr == 1) { gac_text = "Aggro\nGap"; - gac_border = QColor("#ff4b4b"); + gac_border = QColor(255, 75, 75, (255 * btnPerc)); } else if (gacTr == 2) { gac_text = "Mild\nGap"; - gac_border = QColor("#fcff4b"); + gac_border = QColor(252, 255, 75, (255 * btnPerc)); } else { gac_text = "Stock\nGap"; - gac_border = QColor("#4bff66"); + gac_border = QColor(75, 255, 102, (255 * btnPerc)); } } QRect gacBtn(x, y, w, h); p.setPen(QPen(gac_border, 6)); - p.setBrush(QColor(75, 75, 75, 75)); + p.setBrush(QColor(75, 75, 75, (75 * btnPerc))); p.drawEllipse(gacBtn); - p.setPen(QColor(Qt::white)); + p.setPen(QColor(255, 255, 255, (255 * btnPerc))); configFont(p, "Inter", 36, "SemiBold"); p.drawText(gacBtn, Qt::AlignCenter, gac_text); } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index 32c22f949f..993bf42b2d 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -137,6 +137,8 @@ class AnnotatedCameraWidget : public CameraWidget { Q_PROPERTY(bool liveValid MEMBER liveValid); // ############################## DEV UI END ############################## + Q_PROPERTY(float btnPerc MEMBER btnPerc); + public: explicit AnnotatedCameraWidget(VisionStreamType type, QWidget* parent = 0); void updateState(const UIState &s); @@ -263,6 +265,8 @@ private: bool liveValid; // ############################## DEV UI END ############################## + float btnPerc; + protected: void paintGL() override; void initializeGL() override; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index dc8b7737f4..bf37c73e30 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -248,6 +248,7 @@ void ui_update_params(UIState *s) { s->scene.gac_max = std::atoi(params.get("GapAdjustCruiseMax").c_str()); s->scene.dev_ui_enabled = params.getBool("DevUI"); s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str()); + s->scene.button_auto_hide = params.getBool("ButtonAutoHide"); if (s->scene.onroadScreenOff > 0) { s->scene.osoTimer = s->scene.onroadScreenOff * 60 * UI_FREQ; @@ -296,6 +297,50 @@ void UIState::updateStatus() { emit primeTypeChanged(prime_type); Params().put("PrimeType", std::to_string(prime_type)); } + + if (scene.started) { + if (scene.button_auto_hide) { + if (scene.touch_to_wake) { + scene.sleep_btn = 30 * UI_FREQ; + } else if (scene.sleep_btn > 0) { + scene.sleep_btn--; + } else if (scene.sleep_btn == -1) { + scene.sleep_btn = 30 * UI_FREQ; + } + // Check if the sleep button should be fading in + if (scene.sleep_btn_fading_in) { + // Increase the opacity of the sleep button by a small amount + if (scene.sleep_btn_opacity < 20) { + scene.sleep_btn_opacity+= 10; + } + if (scene.sleep_btn_opacity >= 20) { + // If the opacity has reached its maximum value, stop fading in + scene.sleep_btn_fading_in = false; + scene.sleep_btn_opacity = 20; + } + } else if (scene.sleep_btn == 0) { + // Fade out the sleep button as before + if (scene.sleep_btn_opacity > 0) { + scene.sleep_btn_opacity-= 2; + } + } else { + // Set the opacity of the sleep button to its maximum value + scene.sleep_btn_opacity = 20; + } + } else { + scene.sleep_btn_opacity = 20; + } + + if (scene.onroadScreenOff != -2 && scene.touched2) { + scene.sleep_time = scene.osoTimer; + } else if (scene.controlsState.getAlertSize() != cereal::ControlsState::AlertSize::NONE && scene.onroadScreenOff != -2) { + scene.sleep_time = scene.osoTimer; + } else if (scene.sleep_time > 0 && scene.onroadScreenOff != -2) { + scene.sleep_time--; + } else if (scene.sleep_time == -1 && scene.onroadScreenOff != -2) { + scene.sleep_time = scene.osoTimer; + } + } } UIState::UIState(QObject *parent) : QObject(parent) { @@ -369,21 +414,12 @@ void Device::updateBrightness(const UIState &s) { // Scale back to 10% to 100% clipped_brightness = std::clamp(100.0f * clipped_brightness, 10.0f, 100.0f); - if (s.scene.onroadScreenOff != -2 && s.scene.touched2) { - sleep_time = s.scene.osoTimer; - } else if (s.scene.controlsState.getAlertSize() != cereal::ControlsState::AlertSize::NONE && s.scene.onroadScreenOff != -2) { - sleep_time = s.scene.osoTimer; - } else if (sleep_time > 0 && s.scene.onroadScreenOff != -2) { - sleep_time--; - } else if (s.scene.started && sleep_time == -1 && s.scene.onroadScreenOff != -2) { - sleep_time = s.scene.osoTimer; - } } int brightness = brightness_filter.update(clipped_brightness); if (!awake) { brightness = 0; - } else if (s.scene.started && sleep_time == 0 && s.scene.onroadScreenOff != -2) { + } else if (s.scene.started && s.scene.sleep_time == 0 && s.scene.onroadScreenOff != -2) { brightness = s.scene.onroadScreenOffBrightness * 0.01 * brightness; } else if (s.scene.brightness) { brightness = s.scene.brightness * 0.99; diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index eed3f92a6a..a13154aff3 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -159,6 +159,7 @@ typedef struct UIScene { bool visual_brake_lights; int onroadScreenOff, osoTimer, brightness, onroadScreenOffBrightness, awake; + int sleep_time = -1; bool touched2 = false; bool stand_still_timer; @@ -176,6 +177,12 @@ typedef struct UIScene { int rn_offset; bool live_torque_toggle; bool custom_torque_toggle; + + bool touch_to_wake = false; + int sleep_btn = -1; + bool sleep_btn_fading_in = false; + int sleep_btn_opacity = 20; + bool button_auto_hide; } UIScene; class UIState : public QObject { @@ -240,8 +247,6 @@ private: bool motionTriggered(const UIState &s); void setAwake(bool on); - int sleep_time = -1; - signals: void displayPowerChanged(bool on); void interactiveTimout();