diff --git a/selfdrive/assets/fonts/process.py b/selfdrive/assets/fonts/process.py index 643e07f51..2a08ff150 100644 --- a/selfdrive/assets/fonts/process.py +++ b/selfdrive/assets/fonts/process.py @@ -10,7 +10,7 @@ TRANSLATIONS_DIR = SELFDRIVE_DIR / "ui" / "translations" LANGUAGES_FILE = TRANSLATIONS_DIR / "languages.json" GLYPH_PADDING = 6 -EXTRA_CHARS = "–‑✓×°§•X⚙✕◀▶✔⌫⇧␣○●↳çêüñ–‑✓×°§•€£¥²" +EXTRA_CHARS = "–‑✓×°§•X⚙✕◀▶✔⌫⇧␣○●↳çêüñ–‑✓×°§•€£¥²⚠ⓘ" UNIFONT_LANGUAGES = {"ar", "th", "zh-CHT", "zh-CHS", "ko", "ja"} diff --git a/selfdrive/ui/layouts/settings/starpilot/aethergrid.py b/selfdrive/ui/layouts/settings/starpilot/aethergrid.py index ebe76116b..d349935d1 100644 --- a/selfdrive/ui/layouts/settings/starpilot/aethergrid.py +++ b/selfdrive/ui/layouts/settings/starpilot/aethergrid.py @@ -2358,6 +2358,14 @@ class AetherInlineRangeControl(Widget): ) +_ICON_CHARS: dict[str, str] = { + # Swap to "\u26A0"/"\u24D8" after fonts regenerated with process.py + "alert_critical": "!", + "alert_state": "\u25CF", + "alert_info": "\u25CB", +} + + class AetherAdjustorRow(Widget): def __init__( self, @@ -2377,6 +2385,7 @@ class AetherAdjustorRow(Widget): set_active: Callable[[bool], None] | None = None, style: PanelStyle = DEFAULT_PANEL_STYLE, color: rl.Color | None = None, + icon_key: str | None = None, ): super().__init__() self._title = title @@ -2386,6 +2395,8 @@ class AetherAdjustorRow(Widget): self._set_active = set_active self._style = style self._color = color or style.accent + valid_icons = {"sound", "steering", "navigate", "system", "display", "vehicle", "road", "aicar", "first_aid", "alert_critical", "alert_state", "alert_info"} + self._icon_key = icon_key if icon_key in valid_icons else None self._presets = presets or [] self._preset_applied = False self._font_title = gui_app.font(FontWeight.MEDIUM) @@ -2564,7 +2575,27 @@ class AetherAdjustorRow(Widget): self._header_rect = rl.Rectangle(rect.x, rect.y, rect.width, min(rect.height, 78)) self._value_rect = snap_rect(rl.Rectangle(rect.x + rect.width - value_pill_w - 18, value_y, value_pill_w, value_pill_h)) content_right = self._value_rect.x - 18 - content_left = rect.x + 24 + + if self._icon_key: + icon_char = _ICON_CHARS.get(self._icon_key) + if icon_char: + icon_fs = max(18, int(28 * max(0.65, rect.height / 94.0))) + font = gui_app.font(FontWeight.BOLD) + ts = measure_text_cached(font, icon_char, icon_fs) + icon_x = rect.x + 12 + (40.0 - ts.x) / 2 + icon_y = rect.y + (rect.height - ts.y) / 2 + rl.draw_text_ex(font, icon_char, rl.Vector2(icon_x, icon_y), icon_fs, 0, mix_colors(rl.WHITE, self._color, 0.08)) + content_left = rect.x + 12 + 40.0 + 12 + else: + s = (51.0 / 60.0) * max(0.65, rect.height / 94.0) * 1.25 + icon_w = 60.0 * s + icon_x = rect.x + 12 + icon_y = rect.y + (rect.height - icon_w) / 2 + draw_custom_icon(self._icon_key, icon_x, icon_y, s, mix_colors(rl.WHITE, self._color, 0.08)) + content_left = rect.x + 12 + icon_w + 12 + else: + content_left = rect.x + 24 + content_width = max(120.0, content_right - content_left) title_y = rect.y + 14.0 * scale_y if rect.height < 94 else rect.y + 14 @@ -2596,7 +2627,7 @@ class AetherAdjustorRow(Widget): hint_y = rect.y + rect.height - 18.0 * scale_y if rect.height < 94 else rect.y + 76 hint_h = max(6.0, 8.0 * scale_y) if rect.height < 94 else 8 - self._hint_rect = snap_rect(rl.Rectangle(content_left, hint_y, rect.width - 48, hint_h + 4)) + self._hint_rect = snap_rect(rl.Rectangle(content_left, hint_y, rect.x + rect.width - 24 - content_left, hint_h + 4)) hint_track = snap_rect(rl.Rectangle(self._hint_rect.x, self._hint_rect.y + 2, self._hint_rect.width, hint_h)) rl.draw_rectangle_rounded(hint_track, 1.0, 10, rl.Color(255, 255, 255, 10)) fill_w = hint_track.width * self._scrubber._value_fraction(self._current_value()) diff --git a/selfdrive/ui/layouts/settings/starpilot/scribble.py b/selfdrive/ui/layouts/settings/starpilot/scribble.py index 6afba9e11..aa9e16653 100644 --- a/selfdrive/ui/layouts/settings/starpilot/scribble.py +++ b/selfdrive/ui/layouts/settings/starpilot/scribble.py @@ -424,3 +424,5 @@ def draw_custom_icon(key: str, x: float, y: float, s: float, color: rl.Color): rl.draw_line_ex(rl.Vector2(x_c, y_c - 4.0 * s), rl.Vector2(x_c, y_c + 9.0 * s), 3.5 * s, color) rl.draw_line_ex(rl.Vector2(x_c - 6.5 * s, y_c + 2.5 * s), rl.Vector2(x_c + 6.5 * s, y_c + 2.5 * s), 3.5 * s, color) + + diff --git a/selfdrive/ui/layouts/settings/starpilot/sounds.py b/selfdrive/ui/layouts/settings/starpilot/sounds.py index f6d93b78b..783d18c07 100644 --- a/selfdrive/ui/layouts/settings/starpilot/sounds.py +++ b/selfdrive/ui/layouts/settings/starpilot/sounds.py @@ -29,11 +29,6 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import ( draw_section_header, draw_settings_panel_header, AetherSliderDialog, - GROUP_HEADER_HEIGHT, - GROUP_HEADER_GAP, - GROUP_HAIRLINE_COLOR, - GROUP_HEADER_COLOR, - draw_group_header, SECTION_GAP, SECTION_HEADER_HEIGHT, SECTION_HEADER_GAP, @@ -105,6 +100,16 @@ class SoundsManagerView(PanelManagerView): self._active_adjustor_key = None def _init_adjustors(self): + volume_icon_map = { + "WarningImmediateVolume": "alert_critical", + "WarningSoftVolume": "alert_critical", + "RefuseVolume": "alert_critical", + "PromptDistractedVolume": "alert_critical", + "EngageVolume": "alert_state", + "DisengageVolume": "alert_state", + "PromptVolume": "alert_info", + "BelowSteerSpeedVolume": "alert_info", + } for key in self._controller.VOLUME_KEYS: info = self._controller.VOLUME_INFO[key] @@ -122,6 +127,7 @@ class SoundsManagerView(PanelManagerView): set_active=lambda active, k=key: self._show_volume_slider(k) if active else None, style=PANEL_STYLE, color=PANEL_STYLE.accent, + icon_key=volume_icon_map.get(key), ) self._adjustor_rows[key] = adjustor @@ -158,6 +164,7 @@ class SoundsManagerView(PanelManagerView): ) if active else None, style=PANEL_STYLE, color=PANEL_STYLE.accent, + icon_key="alert_info", ) self._adjustor_rows[cd_key] = cd_adjustor @@ -248,9 +255,9 @@ class SoundsManagerView(PanelManagerView): default_adjustor_h = float(AETHER_LIST_METRICS.adjustor_row_height) - # 9 adjustors (8 volume keys + 1 cooldown key) and 2 group headers ("SYSTEM STATE" and "INFORMATIONAL") + # 9 adjustors (8 volume keys + 1 cooldown key) and 2 divider bands between groups left_h = ((len(self._controller.VOLUME_KEYS) + 1) * default_adjustor_h) - left_h += (2 * (GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP)) + left_h += 20 # 2 dividers × (4px band + 6px gap) left_natural_container_h = left_h + 16.0 tiles_needed_h = self.measure_page_grid_height(self._toggle_grid, col_width - 24) + 24 @@ -268,8 +275,8 @@ class SoundsManagerView(PanelManagerView): max_container_h = available_container_h # Scale the left column adjustor rows to fit within max_container_h - # Formula: max_container_h = 9 * left_row_h + 2 * 22 (headers) + 16 (padding) - left_available_for_rows = max_container_h - 44.0 - 16.0 + # Formula: max_container_h = 9 * left_row_h + 2 * 10 (dividers) + 16 (padding) + left_available_for_rows = max_container_h - 20.0 - 16.0 left_row_h = max(60.0, left_available_for_rows / (len(self._controller.VOLUME_KEYS) + 1)) for key in self._controller.VOLUME_KEYS: self._adjustor_rows[key].custom_row_height = left_row_h @@ -336,9 +343,15 @@ class SoundsManagerView(PanelManagerView): ) current_y = y + 8 - for label, keys in groups: + for i, (label, keys) in enumerate(groups): if label is not None: - current_y = draw_group_header(x + 24, current_y, width - 48, label) + divider_h = 4 + divider_color = rl.Color(173, 78, 90, 30) if i == 1 else rl.Color(139, 92, 246, 25) + rl.draw_rectangle_rec( + rl.Rectangle(x + 24, current_y, width - 48, divider_h), + divider_color + ) + current_y += divider_h + 6 for index, key in enumerate(keys): adjustor = self._adjustor_rows[key] row_h = adjustor.measure_height(width)