From 65e1fd299e2fc085c5e3d5b32a366736df85de54 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Wed, 15 Oct 2025 22:53:37 -0700 Subject: [PATCH] raylib: fix full size alert text (#36379) * stash so far * try this * better * fast * rename * revert * clean up * yes * hack to make it work for now * actually fix * fix --- selfdrive/ui/onroad/alert_renderer.py | 20 ++++++++----- .../ui/tests/test_ui/raylib_screenshots.py | 29 ++++++++++++++++++- system/ui/widgets/button.py | 4 +-- system/ui/widgets/label.py | 11 ++++++- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/selfdrive/ui/onroad/alert_renderer.py b/selfdrive/ui/onroad/alert_renderer.py index 362f49a51e..0f944bac52 100644 --- a/selfdrive/ui/onroad/alert_renderer.py +++ b/selfdrive/ui/onroad/alert_renderer.py @@ -7,7 +7,7 @@ from openpilot.system.hardware import TICI from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.widgets import Widget -from openpilot.system.ui.widgets.label import gui_text_box +from openpilot.system.ui.widgets.label import Label AlertSize = log.SelfdriveState.AlertSize AlertStatus = log.SelfdriveState.AlertStatus @@ -74,6 +74,12 @@ class AlertRenderer(Widget): self.font_regular: rl.Font = gui_app.font(FontWeight.NORMAL) self.font_bold: rl.Font = gui_app.font(FontWeight.BOLD) + # font size is set dynamically + self._full_text1_label = Label("", font_size=0, font_weight=FontWeight.BOLD, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER, + text_alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_TOP) + self._full_text2_label = Label("", font_size=ALERT_FONT_BIG, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER, + text_alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_TOP) + def get_alert(self, sm: messaging.SubMaster) -> Alert | None: """Generate the current alert based on selfdrive state.""" ss = sm['selfdriveState'] @@ -153,16 +159,16 @@ class AlertRenderer(Widget): is_long = len(alert.text1) > 15 font_size1 = 132 if is_long else 177 - align_center = rl.GuiTextAlignment.TEXT_ALIGN_CENTER - align_top = rl.GuiTextAlignmentVertical.TEXT_ALIGN_TOP - - top_offset = 240 if is_long else 270 + top_offset = 200 if is_long or '\n' in alert.text1 else 270 title_rect = rl.Rectangle(rect.x, rect.y + top_offset, rect.width, 600) - gui_text_box(title_rect, alert.text1, font_size1, alignment=align_center, alignment_vertical=align_top, font_weight=FontWeight.BOLD) + self._full_text1_label.set_font_size(font_size1) + self._full_text1_label.set_text(alert.text1) + self._full_text1_label.render(title_rect) bottom_offset = 361 if is_long else 420 subtitle_rect = rl.Rectangle(rect.x, rect.y + rect.height - bottom_offset, rect.width, 300) - gui_text_box(subtitle_rect, alert.text2, ALERT_FONT_BIG, alignment=align_center, alignment_vertical=align_top) + self._full_text2_label.set_text(alert.text2) + self._full_text2_label.render(subtitle_rect) def _draw_centered(self, text, rect, font, font_size, center_y=True, color=rl.WHITE) -> None: text_size = measure_text_cached(font, text, font_size) diff --git a/selfdrive/ui/tests/test_ui/raylib_screenshots.py b/selfdrive/ui/tests/test_ui/raylib_screenshots.py index 013287aaeb..6de774648a 100755 --- a/selfdrive/ui/tests/test_ui/raylib_screenshots.py +++ b/selfdrive/ui/tests/test_ui/raylib_screenshots.py @@ -182,12 +182,37 @@ def setup_onroad_medium_alert(click, pm: PubMaster): def setup_onroad_full_alert(click, pm: PubMaster): + setup_onroad(click, pm) + alert = messaging.new_message('selfdriveState') + alert.selfdriveState.alertSize = AlertSize.full + alert.selfdriveState.alertText1 = "DISENGAGE IMMEDIATELY" + alert.selfdriveState.alertText2 = "Driver Distracted" + alert.selfdriveState.alertStatus = AlertStatus.critical + for _ in range(5): + pm.send('selfdriveState', alert) + alert.clear_write_flag() + time.sleep(0.05) + + +def setup_onroad_full_alert_multiline(click, pm: PubMaster): + setup_onroad(click, pm) + alert = messaging.new_message('selfdriveState') + alert.selfdriveState.alertSize = AlertSize.full + alert.selfdriveState.alertText1 = "Reverse\nGear" + alert.selfdriveState.alertStatus = AlertStatus.normal + for _ in range(5): + pm.send('selfdriveState', alert) + alert.clear_write_flag() + time.sleep(0.05) + + +def setup_onroad_full_alert_long_text(click, pm: PubMaster): setup_onroad(click, pm) alert = messaging.new_message('selfdriveState') alert.selfdriveState.alertSize = AlertSize.full alert.selfdriveState.alertText1 = "TAKE CONTROL IMMEDIATELY" alert.selfdriveState.alertText2 = "Calibration Invalid: Remount Device & Recalibrate" - alert.selfdriveState.alertStatus = AlertStatus.critical + alert.selfdriveState.alertStatus = AlertStatus.userPrompt for _ in range(5): pm.send('selfdriveState', alert) alert.clear_write_flag() @@ -218,6 +243,8 @@ CASES = { "onroad_small_alert": setup_onroad_small_alert, "onroad_medium_alert": setup_onroad_medium_alert, "onroad_full_alert": setup_onroad_full_alert, + "onroad_full_alert_multiline": setup_onroad_full_alert_multiline, + "onroad_full_alert_long_text": setup_onroad_full_alert_long_text, } diff --git a/system/ui/widgets/button.py b/system/ui/widgets/button.py index fa6e5ed7dc..15d48b4e13 100644 --- a/system/ui/widgets/button.py +++ b/system/ui/widgets/button.py @@ -96,8 +96,8 @@ class Button(Widget): self._border_radius = border_radius self._background_color = BUTTON_BACKGROUND_COLORS[self._button_style] - self._label = Label(text, font_size, font_weight, text_alignment, text_padding, - BUTTON_TEXT_COLOR[self._button_style], icon=icon) + self._label = Label(text, font_size, font_weight, text_alignment, text_padding=text_padding, + text_color=BUTTON_TEXT_COLOR[self._button_style], icon=icon) self._click_callback = click_callback self._multi_touch = multi_touch diff --git a/system/ui/widgets/label.py b/system/ui/widgets/label.py index 32cc7063d2..99aed529a7 100644 --- a/system/ui/widgets/label.py +++ b/system/ui/widgets/label.py @@ -94,6 +94,7 @@ class Label(Widget): font_size: int = DEFAULT_TEXT_SIZE, font_weight: FontWeight = FontWeight.NORMAL, text_alignment: int = rl.GuiTextAlignment.TEXT_ALIGN_CENTER, + text_alignment_vertical: int = rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, text_padding: int = 0, text_color: rl.Color = DEFAULT_TEXT_COLOR, icon: Union[rl.Texture, None] = None, # noqa: UP007 @@ -104,6 +105,7 @@ class Label(Widget): self._font = gui_app.font(self._font_weight) self._font_size = font_size self._text_alignment = text_alignment + self._text_alignment_vertical = text_alignment_vertical self._text_padding = text_padding self._text_color = text_color self._icon = icon @@ -118,6 +120,10 @@ class Label(Widget): def set_text_color(self, color): self._text_color = color + def set_font_size(self, size): + self._font_size = size + self._update_text(self._text) + def _update_layout_rects(self): self._update_text(self._text) @@ -131,7 +137,10 @@ class Label(Widget): def _render(self, _): text_size = self._text_size[0] if self._text_size else rl.Vector2(0.0, 0.0) - text_pos = rl.Vector2(self._rect.x, (self._rect.y + (self._rect.height - text_size.y) // 2)) + if self._text_alignment_vertical == rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE: + text_pos = rl.Vector2(self._rect.x, (self._rect.y + (self._rect.height - text_size.y) // 2)) + else: + text_pos = rl.Vector2(self._rect.x, self._rect.y) if self._icon: icon_y = self._rect.y + (self._rect.height - self._icon.height) / 2