From dab51a864f896a2afa10af68637eb7464f0fa94f Mon Sep 17 00:00:00 2001 From: Daniel Koepping Date: Wed, 29 Apr 2026 15:26:55 -0700 Subject: [PATCH] show alert severity (#37931) * alert icons, sort by severity * rename --- selfdrive/ui/mici/layouts/home.py | 26 ++++++++++++++++----- selfdrive/ui/mici/layouts/main.py | 1 + selfdrive/ui/mici/layouts/offroad_alerts.py | 10 ++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/selfdrive/ui/mici/layouts/home.py b/selfdrive/ui/mici/layouts/home.py index cbe7ec29f..8a71e2efe 100644 --- a/selfdrive/ui/mici/layouts/home.py +++ b/selfdrive/ui/mici/layouts/home.py @@ -39,11 +39,16 @@ class AlertsPill(Widget): self.set_rect(rl.Rectangle(0, 0, 104, 52)) self._pill_bg_txt = gui_app.texture("icons_mici/alerts_pill.png", 104, 52) - self._warning_txt = gui_app.texture("icons_mici/offroad_alerts/red_warning.png", 36, 36) + self._icon_red = gui_app.texture("icons_mici/offroad_alerts/red_warning.png", 36, 36) + self._icon_orange = gui_app.texture("icons_mici/offroad_alerts/orange_warning.png", 36, 36) + self._icon_green = gui_app.texture("icons_mici/offroad_alerts/green_wheel.png", 36, 36) self._alert_count_callback: Callable[[], int] | None = None + self._max_severity_callback: Callable[[], int | None] | None = None - def set_alert_count_callback(self, callback: Callable[[], int] | None): + def set_alert_count_callback(self, callback: Callable[[], int] | None, + severity_callback: Callable[[], int | None] | None = None): self._alert_count_callback = callback + self._max_severity_callback = severity_callback def _render(self, _): alert_count = self._alert_count_callback() if self._alert_count_callback else 0 @@ -51,9 +56,17 @@ class AlertsPill(Widget): pill_w, pill_h = self._pill_bg_txt.width, self._pill_bg_txt.height rl.draw_texture_ex(self._pill_bg_txt, rl.Vector2(self.rect.x, self.rect.y), 0.0, 1.0, rl.WHITE) + severity = self._max_severity_callback() if self._max_severity_callback else None + if severity == -1: + warning_txt = self._icon_green + elif severity is not None and severity > 0: + warning_txt = self._icon_red + else: + warning_txt = self._icon_orange + warn_x = self.rect.x + self.ICON_OFFSET - warn_y = self.rect.y + (pill_h - self._warning_txt.height) / 2 - rl.draw_texture_ex(self._warning_txt, rl.Vector2(warn_x, warn_y), 0.0, 1.0, rl.WHITE) + warn_y = self.rect.y + (pill_h - warning_txt.height) / 2 + rl.draw_texture_ex(warning_txt, rl.Vector2(warn_x, warn_y), 0.0, 1.0, rl.WHITE) count_rect = rl.Rectangle(self.rect.x + self.COUNT_OFFSET, self.rect.y, pill_w - self.COUNT_OFFSET, pill_h) gui_label(count_rect, str(alert_count), font_size=36, @@ -181,11 +194,12 @@ class MiciHomeLayout(Widget): self._update_params() def set_callbacks(self, on_settings: Callable | None = None, on_alerts: Callable | None = None, - alert_count_callback: Callable[[], int] | None = None): + alert_count_callback: Callable[[], int] | None = None, + max_severity_callback: Callable[[], int | None] | None = None): self._on_settings_click = on_settings self._on_alerts_click = on_alerts self._alert_count_callback = alert_count_callback - self._alerts_pill.set_alert_count_callback(alert_count_callback) + self._alerts_pill.set_alert_count_callback(alert_count_callback, max_severity_callback) def _handle_mouse_release(self, mouse_pos: MousePos): if not self._did_long_press: diff --git a/selfdrive/ui/mici/layouts/main.py b/selfdrive/ui/mici/layouts/main.py index badfbe315..9b4bcb5cc 100644 --- a/selfdrive/ui/mici/layouts/main.py +++ b/selfdrive/ui/mici/layouts/main.py @@ -71,6 +71,7 @@ class MiciMainLayout(Scroller): on_settings=lambda: gui_app.push_widget(self._settings_layout), on_alerts=lambda: self._scroll_to(self._alerts_layout), alert_count_callback=self._alerts_layout.active_alerts, + max_severity_callback=self._alerts_layout.max_severity, ) for layout in (self._car_onroad_layout, self._body_onroad_layout): layout.set_click_callback(lambda: self._scroll_to(self._home_layout)) diff --git a/selfdrive/ui/mici/layouts/offroad_alerts.py b/selfdrive/ui/mici/layouts/offroad_alerts.py index 0dae5d207..a46002c28 100644 --- a/selfdrive/ui/mici/layouts/offroad_alerts.py +++ b/selfdrive/ui/mici/layouts/offroad_alerts.py @@ -208,6 +208,9 @@ class MiciOffroadAlerts(Scroller): def active_alerts(self) -> int: return sum(alert.visible for alert in self.sorted_alerts) + def max_severity(self) -> int | None: + return max((alert.severity for alert in self.sorted_alerts if alert.visible), default=None) + def scrolling(self): return self._scroller.scroll_panel.is_touch_valid() @@ -273,6 +276,11 @@ class MiciOffroadAlerts(Scroller): if alert_json: text = alert_json.get("text", "").replace("%1", alert_json.get("extra", "")) + if text and not alert_data.visible: + # Bump newly visible alerts to the top, severity sort keeps it at the top of its category + widget = next(w for w in self._scroller.items if w.alert_data is alert_data) + self._scroller.items.remove(widget) + self._scroller.items.insert(0, widget) alert_data.text = text alert_data.visible = bool(text) @@ -283,6 +291,8 @@ class MiciOffroadAlerts(Scroller): for alert_item in self.alert_items: alert_item.update_alert_data(alert_item.alert_data) + self._scroller.items.sort(key=lambda w: -w.alert_data.severity) + return active_count def show_event(self):