From 3c3969b09d24f148b665dbcb6c8a34092dfeeb48 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Mon, 11 May 2026 00:36:41 -0500 Subject: [PATCH] exp c4 ui --- selfdrive/ui/lib/starpilot_mode_banner.py | 60 +++++++++++++++++++ selfdrive/ui/lib/starpilot_status.py | 16 +++++ .../ui/mici/onroad/augmented_road_view.py | 55 ++--------------- selfdrive/ui/onroad/augmented_road_view.py | 6 ++ 4 files changed, 86 insertions(+), 51 deletions(-) create mode 100644 selfdrive/ui/lib/starpilot_mode_banner.py diff --git a/selfdrive/ui/lib/starpilot_mode_banner.py b/selfdrive/ui/lib/starpilot_mode_banner.py new file mode 100644 index 000000000..c74fffd63 --- /dev/null +++ b/selfdrive/ui/lib/starpilot_mode_banner.py @@ -0,0 +1,60 @@ +import time + +import pyray as rl + +from openpilot.selfdrive.ui.lib.starpilot_status import get_border_color, get_mode_transition_banner_text +from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.system.ui.lib.application import FontWeight +from openpilot.system.ui.widgets.label import UnifiedLabel + + +class ModeTransitionBanner: + SHOW_TIME_SECONDS = 2.5 + + def __init__(self, *, font_size: int = 34, width: int = 520, height: int = 72, top_margin: int = 22): + self._last_mode: str | None = None + self._visible_until = 0.0 + self._width = width + self._height = height + self._top_margin = top_margin + self._label = UnifiedLabel( + "", + font_size, + FontWeight.BOLD, + text_color=rl.WHITE, + alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER, + alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, + ) + + def update(self): + if not ui_state.started: + self._last_mode = None + self._visible_until = 0.0 + return + + current_mode = get_mode_transition_banner_text(ui_state) + if self._last_mode is None: + self._last_mode = current_mode + return + + if current_mode != self._last_mode: + self._last_mode = current_mode + if current_mode is not None: + self._label.set_text(f"{current_mode} MODE") + self._visible_until = time.monotonic() + self.SHOW_TIME_SECONDS + + def render(self, rect: rl.Rectangle): + if not ui_state.started or time.monotonic() > self._visible_until: + return + + banner_width = min(rect.width - 120, self._width) + banner_rect = rl.Rectangle( + rect.x + (rect.width - banner_width) / 2, + rect.y + self._top_margin, + banner_width, + self._height, + ) + + rl.draw_rectangle_rounded(banner_rect, 0.3, 12, rl.Color(0, 0, 0, 175)) + rl.draw_rectangle_rounded_lines_ex(banner_rect, 0.3, 12, 4, get_border_color(ui_state)) + self._label.render(banner_rect) diff --git a/selfdrive/ui/lib/starpilot_status.py b/selfdrive/ui/lib/starpilot_status.py index 092d79ea6..5dadd5e11 100644 --- a/selfdrive/ui/lib/starpilot_status.py +++ b/selfdrive/ui/lib/starpilot_status.py @@ -74,3 +74,19 @@ def get_experimental_mode_banner_text(state: UIState): if state.sm["selfdriveState"].experimentalMode: return "EXPERIMENTAL" return "CHILL" + + +def get_mode_transition_banner_text(state: UIState): + enabled = state.sm["selfdriveState"].enabled + lateral_active = enabled or state.always_on_lateral_active + conditional_enabled = state.params.get_bool("ConditionalExperimental") + + if state.status == UIStatus.OVERRIDE: + return "OVERRIDE" + if state.switchback_mode_enabled and lateral_active: + return "SWITCHBACK" + if conditional_enabled and enabled and state.conditional_status in CEM_MANUAL_OVERRIDE_STATUSES: + return "OVERRIDDEN" + if enabled and state.sm["selfdriveState"].experimentalMode: + return "EXPERIMENTAL" + return None diff --git a/selfdrive/ui/mici/onroad/augmented_road_view.py b/selfdrive/ui/mici/onroad/augmented_road_view.py index 95a8f93e2..4fdbb5947 100644 --- a/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -17,8 +17,8 @@ from openpilot.selfdrive.ui.mici.onroad.starpilot_status import ( EXPERIMENTAL_COLOR, TRAFFIC_COLOR, get_border_color, - get_experimental_mode_banner_text, ) +from openpilot.selfdrive.ui.lib.starpilot_mode_banner import ModeTransitionBanner from openpilot.selfdrive.ui.mici.onroad.cameraview import CameraView from openpilot.selfdrive.ui.lib.starpilot_visuals import get_border_width from openpilot.system.ui.lib.application import FontWeight, gui_app, MousePos, MouseEvent @@ -147,54 +147,6 @@ class BookmarkIcon(Widget): rl.draw_texture(self._icon, int(icon_x), int(icon_y), rl.WHITE) -class ExperimentalModeBanner(Widget): - SHOW_TIME_SECONDS = 2.5 - - def __init__(self): - super().__init__() - self._last_mode: str | None = None - self._visible_until = 0.0 - self._label = UnifiedLabel( - "", - 34, - FontWeight.BOLD, - text_color=rl.WHITE, - alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER, - alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, - ) - - def _update_state(self): - current_mode = get_experimental_mode_banner_text(ui_state) - if current_mode is None: - return - - if self._last_mode is None: - self._last_mode = current_mode - return - - if current_mode != self._last_mode: - self._last_mode = current_mode - self._label.set_text(f"{current_mode} MODE") - self._visible_until = time.monotonic() + self.SHOW_TIME_SECONDS - - def _render(self, rect): - if not ui_state.started or time.monotonic() > self._visible_until: - return - - banner_width = min(rect.width - 120, 520) - banner_height = 72 - banner_rect = rl.Rectangle( - rect.x + (rect.width - banner_width) / 2, - rect.y + 22, - banner_width, - banner_height, - ) - - rl.draw_rectangle_rounded(banner_rect, 0.3, 12, rl.Color(0, 0, 0, 175)) - rl.draw_rectangle_rounded_lines_ex(banner_rect, 0.3, 12, 4, get_border_color(ui_state)) - self._label.render(banner_rect) - - class MinSteerSpeedBanner(Widget): """One-shot-per-drive banner shown for the full first below-min-steer interval.""" @@ -420,7 +372,7 @@ class AugmentedRoadView(CameraView): self._alert_renderer = AlertRenderer() self._driver_state_renderer = DriverStateRenderer() self._confidence_ball = ConfidenceBall() - self._experimental_mode_banner = ExperimentalModeBanner() + self._mode_transition_banner = ModeTransitionBanner() self._min_steer_speed_banner = MinSteerSpeedBanner() self._standstill_timer = StandstillTimerOverlay() self._offroad_label = UnifiedLabel("start the car to\nuse openpilot", 54, FontWeight.DISPLAY, @@ -536,13 +488,14 @@ class AugmentedRoadView(CameraView): self._hud_renderer.set_can_draw_top_icons((not in_reverse) and (not is_driver_stream) and (alert_to_render is None)) self._hud_renderer.set_wheel_critical_icon((not in_reverse) and (not is_driver_stream) and alert_to_render is not None and not not_animating_out and alert_to_render.visual_alert == car.CarControl.HUDControl.VisualAlert.steerRequired) + self._mode_transition_banner.update() # TODO: have alert renderer draw offroad mici label below if ui_state.started: self._alert_renderer.render(self._content_rect) if not in_reverse and not is_driver_stream: self._hud_renderer.render_foreground() if (not in_reverse) and (not is_driver_stream) and alert_to_render is None: - self._experimental_mode_banner.render(self._content_rect) + self._mode_transition_banner.render(self._content_rect) rendered_standstill_timer = False if not in_reverse and not is_driver_stream: rendered_standstill_timer = self._standstill_timer.render(self._content_rect, in_reverse) diff --git a/selfdrive/ui/onroad/augmented_road_view.py b/selfdrive/ui/onroad/augmented_road_view.py index d4c243eb2..013304fe3 100644 --- a/selfdrive/ui/onroad/augmented_road_view.py +++ b/selfdrive/ui/onroad/augmented_road_view.py @@ -12,6 +12,7 @@ from openpilot.selfdrive.ui.onroad.driver_state import DriverStateRenderer from openpilot.selfdrive.ui.onroad.hud_renderer import HudRenderer from openpilot.selfdrive.ui.onroad.model_renderer import ModelRenderer from openpilot.selfdrive.ui.onroad.cameraview import CameraView +from openpilot.selfdrive.ui.lib.starpilot_mode_banner import ModeTransitionBanner from openpilot.selfdrive.ui.lib.starpilot_status import get_screen_edge_color from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCameraConfig, view_frame_from_device_frame @@ -149,6 +150,7 @@ class AugmentedRoadView(CameraView): self._hud_renderer = HudRenderer() self.alert_renderer = AlertRenderer() self.driver_state_renderer = DriverStateRenderer() + self._mode_transition_banner = ModeTransitionBanner() self._min_steer_speed_banner = MinSteerSpeedBanner() # debug @@ -188,10 +190,14 @@ class AugmentedRoadView(CameraView): super()._render(self._content_rect) # Draw all UI overlays + current_alert = self.alert_renderer.get_alert(ui_state.sm) self.model_renderer.render(self._content_rect) self._hud_renderer.render(self._content_rect) + self._mode_transition_banner.update() self.alert_renderer.render(self._content_rect) self.driver_state_renderer.render(self._content_rect) + if current_alert is None: + self._mode_transition_banner.render(self._content_rect) self._min_steer_speed_banner.render(self._content_rect) # Custom UI extension point - add custom overlays here