diff --git a/selfdrive/ui/layouts/settings/starpilot/sounds.py b/selfdrive/ui/layouts/settings/starpilot/sounds.py index cca0941ea6..a3207ba1a2 100644 --- a/selfdrive/ui/layouts/settings/starpilot/sounds.py +++ b/selfdrive/ui/layouts/settings/starpilot/sounds.py @@ -282,15 +282,18 @@ class SoundsManagerView(Widget): left_h += GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP left_h += GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP left_h += GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP + left_column_total_h = left_h + 24 cd_h = self._adjustor_rows[self._controller.COOLDOWN_KEY].measure_height(col_width) - group_h = GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP - self._tile_grid_h = left_h - cd_h - group_h - - right_h = cd_h + group_h + self._tile_grid_h + + tile_rows = self._toggle_grid.get_row_count(len(self._toggle_grid.tiles), available_width=col_width) + tile_gaps = self._toggle_grid.get_internal_gap_height(len(self._toggle_grid.tiles), available_width=col_width) + tiles_content_h = tile_rows * 130 + tile_gaps + + right_column_total_h = cd_h + SECTION_GAP + (GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP) + (tiles_content_h + 24) section_overhead = SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP - return section_overhead + max(left_h, right_h) + 12.0 + return section_overhead + max(left_column_total_h, right_column_total_h) + 12.0 def _draw_header(self, rect: rl.Rectangle): draw_settings_panel_header(rect, tr("Sounds & Alerts"), tr("Manage system volumes and custom alert toggles."), subtitle_size=24) @@ -324,11 +327,8 @@ class SoundsManagerView(Widget): ) y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP - col_left = rl.Rectangle(rect.x, y, col_width, self._content_height) - col_right = rl.Rectangle(rect.x + col_width + SECTION_GAP, y, col_width, self._content_height) - - self._draw_volume_column(col_left) - self._draw_utility_column(col_right) + self._draw_volume_column(y, rect.x, col_width) + self._draw_utility_column(y, rect.x + col_width + SECTION_GAP, col_width) def _draw_group_header(self, x: float, y: float, width: float, label: str) -> float: gui_label(rl.Rectangle(x, y, width, GROUP_HEADER_HEIGHT), label, 14, GROUP_HEADER_COLOR, FontWeight.MEDIUM) @@ -336,7 +336,7 @@ class SoundsManagerView(Widget): rl.draw_line(int(x), int(y), int(x + width), int(y), GROUP_HAIRLINE_COLOR) return y + GROUP_HEADER_GAP - def _draw_volume_column(self, rect: rl.Rectangle): + def _draw_volume_column(self, y: float, x: float, width: float): safety_keys = ["WarningImmediateVolume", "WarningSoftVolume", "RefuseVolume", "PromptDistractedVolume"] system_keys = ["EngageVolume", "DisengageVolume"] info_keys = ["PromptVolume", "BelowSteerSpeedVolume"] @@ -347,44 +347,48 @@ class SoundsManagerView(Widget): (tr("INFORMATIONAL"), info_keys), ] - total_h = sum(GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP + sum(self._adjustor_rows[k].measure_height(rect.width) for k in keys) for _, keys in groups) + total_h = sum(GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP + sum(self._adjustor_rows[k].measure_height(width) for k in keys) for _, keys in groups) draw_list_group_shell( - rl.Rectangle(rect.x - 12, rect.y - 12, rect.width + 24, total_h + 24), + rl.Rectangle(x, y, width, total_h + 24), style=PANEL_STYLE ) - current_y = rect.y + current_y = y + 12 for label, keys in groups: - current_y = self._draw_group_header(rect.x, current_y, rect.width, label) + current_y = self._draw_group_header(x + 24, current_y, width - 48, label) for key in keys: adjustor = self._adjustor_rows[key] - row_h = adjustor.measure_height(rect.width) - row_rect = rl.Rectangle(rect.x, current_y, rect.width, row_h) + row_h = adjustor.measure_height(width) + row_rect = rl.Rectangle(x, current_y, width, row_h) adjustor.set_is_last(True) adjustor.set_parent_rect(self._scroll_rect) adjustor.render(row_rect) current_y += row_h - def _draw_utility_column(self, rect: rl.Rectangle): - current_y = rect.y + def _draw_utility_column(self, y: float, x: float, width: float): + current_y = y cd_key = self._controller.COOLDOWN_KEY adjustor = self._adjustor_rows[cd_key] - row_h = adjustor.measure_height(rect.width) + row_h = adjustor.measure_height(width) + + draw_list_group_shell(rl.Rectangle(x, current_y, width, row_h), style=PANEL_STYLE) + adjustor.set_is_last(True) adjustor.set_parent_rect(self._scroll_rect) - adjustor.render(rl.Rectangle(rect.x, current_y, rect.width, row_h)) - current_y += row_h + adjustor.render(rl.Rectangle(x, current_y, width, row_h)) + current_y += row_h + SECTION_GAP - current_y = self._draw_group_header(rect.x, current_y, rect.width, tr("CUSTOM ALERTS")) + current_y = self._draw_group_header(x + 24, current_y, width - 48, tr("CUSTOM ALERTS")) - tile_grid_h = self._tile_grid_h + tile_rows = self._toggle_grid.get_row_count(len(self._toggle_grid.tiles), available_width=width) + tile_gaps = self._toggle_grid.get_internal_gap_height(len(self._toggle_grid.tiles), available_width=width) + tiles_content_h = tile_rows * 130 + tile_gaps - tile_grid_rect = rl.Rectangle(rect.x - 12, current_y - 12, rect.width + 24, tile_grid_h + 24) - draw_list_group_shell(tile_grid_rect, style=PANEL_STYLE) + draw_list_group_shell(rl.Rectangle(x, current_y, width, tiles_content_h + 24), style=PANEL_STYLE) self._toggle_grid.set_parent_rect(self._scroll_rect) - self._toggle_grid.render(rl.Rectangle(rect.x, current_y, rect.width, tile_grid_h)) + self._toggle_grid.render(rl.Rectangle(x + 12, current_y + 12, width - 24, tiles_content_h)) class StarPilotSoundsLayout(_SettingsPage): diff --git a/selfdrive/ui/layouts/settings/starpilot/system_settings.py b/selfdrive/ui/layouts/settings/starpilot/system_settings.py index f56a945c5c..cc8beacde0 100644 --- a/selfdrive/ui/layouts/settings/starpilot/system_settings.py +++ b/selfdrive/ui/layouts/settings/starpilot/system_settings.py @@ -1,4 +1,5 @@ from __future__ import annotations +from dataclasses import replace import json import os import re @@ -95,6 +96,12 @@ ROW_HEIGHT = AETHER_LIST_METRICS.row_height FADE_HEIGHT = AETHER_LIST_METRICS.fade_height PANEL_STYLE = panel_style_from_color("#D946EF") +SYSTEM_PANEL_METRICS = replace( + AETHER_LIST_METRICS, + outer_margin_y=14, + panel_padding_bottom=14, +) + class SystemSettingsManagerView(AetherInteractiveMixin, Widget): HEADER_SUBTITLE_HEIGHT = 24 @@ -454,7 +461,7 @@ class SystemSettingsManagerView(AetherInteractiveMixin, Widget): self._interactive_rects.clear() self.set_rect(rect) - frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE) + frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE, metrics=SYSTEM_PANEL_METRICS) self._scroll_rect = scroll_rect self._drive_mode_control.set_parent_rect(frame.header) @@ -504,33 +511,22 @@ class SystemSettingsManagerView(AetherInteractiveMixin, Widget): icon_color = PANEL_STYLE.accent if (hovered or pressed) else AetherListColors.HEADER draw_custom_icon("first_aid", icon_x, icon_y, s, icon_color) - summary_y = rect.y + 48 + self.HEADER_SUBTITLE_HEIGHT + self.HEADER_SUMMARY_GAP - summary_rect = rl.Rectangle(rect.x, summary_y, rect.width, min(self.HEADER_CARD_HEIGHT, rect.y + rect.height - summary_y)) - self._draw_summary_card(summary_rect) + content_width = rect.width - AETHER_LIST_METRICS.content_right_gutter + column_w = (content_width - self.COLUMN_GAP) / 2 + summary_y = rect.y + 92 - def _draw_summary_card(self, rect: rl.Rectangle): - draw_soft_card(rect, PANEL_STYLE.surface_fill, PANEL_STYLE.surface_border) - inset = 18 - - # Left Column: Huge Segmented Control - control_w = max(420.0, min(540.0, rect.width * 0.46)) - control_x = rect.x + inset - control_h = 96.0 - control_y = rect.y + (rect.height - control_h) / 2 - - control_rect = rl.Rectangle(control_x, control_y, control_w, control_h) + # Left Column: Auto/Onroad/Offroad + control_rect = rl.Rectangle(rect.x, summary_y, column_w, 108) self._drive_mode_control.render(control_rect) - # Right Column: Labels & Metrics - right_x = control_x + control_w + 32 - right_w = rect.x + rect.width - inset - right_x + # Right Column: System Status Card + status_rect = rl.Rectangle(rect.x + column_w + self.COLUMN_GAP, summary_y, column_w, 108) + draw_soft_card(status_rect, rl.Color(255, 255, 255, 4), rl.Color(255, 255, 255, 14)) - # Header Labels - header_y = rect.y + 12 - gui_label(rl.Rectangle(right_x, header_y, right_w, 20), + header_y = status_rect.y + 12 + gui_label(rl.Rectangle(status_rect.x + 20, header_y, status_rect.width - 40, 20), tr("System Status"), 16, AetherListColors.MUTED, FontWeight.SEMI_BOLD) - # Metrics metric_rows = [ (tr("Storage"), self._controller.storage_summary()), (tr("System Backups"), self._controller.backup_count_text()), @@ -538,33 +534,33 @@ class SystemSettingsManagerView(AetherInteractiveMixin, Widget): ] metric_row_h = 16 metric_row_gap = 4 - metric_start_y = rect.y + 42 + metric_start_y = status_rect.y + 40 label_font = gui_app.font(FontWeight.MEDIUM) + label_w = 180.0 for i, (label, value) in enumerate(metric_rows): row_y = metric_start_y + i * (metric_row_h + metric_row_gap) - label_w_metric = measure_text_cached(label_font, label, 16).x + 4 - gui_label(rl.Rectangle(right_x, row_y, label_w_metric, metric_row_h + 2), + gui_label(rl.Rectangle(status_rect.x + 20, row_y, label_w, metric_row_h + 2), label, 16, AetherListColors.MUTED, FontWeight.MEDIUM) - value_x = right_x + label_w_metric + 12 - gui_label(rl.Rectangle(value_x, row_y, right_x + right_w - value_x, metric_row_h + 2), + value_x = status_rect.x + 20 + label_w + gui_label(rl.Rectangle(value_x, row_y, status_rect.x + status_rect.width - 20 - value_x, metric_row_h + 2), value, 16, AetherListColors.HEADER, FontWeight.MEDIUM) def _measure_content_height(self, width: float) -> float: display_h = self._section_block_height(self._slider_section_height(self._display_slider_keys, width)) power_h = self._section_block_height(self._slider_section_height(self._power_slider_keys, width)) + + tile_rows = self._connectivity_tile_grid.get_row_count( + len(self._connectivity_tile_grid.tiles), available_width=width) + tile_gaps = self._connectivity_tile_grid.get_internal_gap_height( + len(self._connectivity_tile_grid.tiles), available_width=width) + tiles_content_h = tile_rows * 130 + tile_gaps + if self._uses_two_columns(width): - left_col = display_h + SECTION_GAP + power_h - self._basics_tile_grid_h = left_col - return left_col + min_h = self._scroll_rect.height if self._scroll_rect else 0.0 + return max(min_h, display_h + SECTION_GAP + power_h) else: - tile_rows = self._connectivity_tile_grid.get_row_count( - len(self._connectivity_tile_grid.tiles), available_width=width) - tile_gaps = self._connectivity_tile_grid.get_internal_gap_height( - len(self._connectivity_tile_grid.tiles), available_width=width) - tiles_content_h = tile_rows * 96 + tile_gaps - connectivity_h = tiles_content_h - return self._stacked_section_height([display_h, power_h, connectivity_h]) + return self._stacked_section_height([display_h, power_h, tiles_content_h + 24]) def _section_block_height(self, content_height: float) -> float: return SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + content_height @@ -583,10 +579,21 @@ class SystemSettingsManagerView(AetherInteractiveMixin, Widget): def _draw_basics_tab(self, y: float, x: float, width: float): if self._uses_two_columns(width): column_w = self._column_width(width) - y2 = self._draw_slider_section(y, x, column_w, tr("Display"), self._display_slider_keys) - y2 += SECTION_GAP - self._draw_slider_section(y2, x, column_w, tr("Power"), self._power_slider_keys) - self._draw_connectivity_tiles_column(y, x + column_w + self.COLUMN_GAP, column_w) + display_container_h = self._slider_section_height(self._display_slider_keys, column_w) + power_container_h = self._slider_section_height(self._power_slider_keys, column_w) + header_overhead = (SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP) * 2 + + viewport_h = self._scroll_rect.height if self._scroll_rect else 0.0 + needed_gap = viewport_h - (display_container_h + power_container_h + header_overhead) + section_gap = max(AETHER_LIST_METRICS.section_gap, needed_gap) + + display_bottom = self._draw_slider_section(y, x, column_w, tr("Display"), self._display_slider_keys) + power_y = display_bottom + section_gap + power_bottom = self._draw_slider_section(power_y, x, column_w, tr("Power"), self._power_slider_keys) + + container_top = y + SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + container_height = power_bottom - container_top + self._draw_connectivity_tiles_column(container_top, x + column_w + self.COLUMN_GAP, column_w, container_height) return y = self._draw_slider_section(y, x, width, tr("Display"), self._display_slider_keys) y += SECTION_GAP @@ -594,21 +601,19 @@ class SystemSettingsManagerView(AetherInteractiveMixin, Widget): y += SECTION_GAP self._draw_connectivity_tiles_section(y, x, width) - def _draw_connectivity_tiles_column(self, y: float, x: float, width: float): - tile_h = self._basics_tile_grid_h - shell_rect = rl.Rectangle(x - 12, y - 12, width + 24, tile_h + 24) - draw_list_group_shell(shell_rect, style=PANEL_STYLE) + def _draw_connectivity_tiles_column(self, y: float, x: float, width: float, height: float): + draw_list_group_shell(rl.Rectangle(x, y, width, height), style=PANEL_STYLE) self._connectivity_tile_grid.set_parent_rect(self._scroll_rect) - self._connectivity_tile_grid.render(rl.Rectangle(x, y, width, tile_h)) + self._connectivity_tile_grid.render(rl.Rectangle(x + 12, y + 12, width - 24, height - 24)) def _draw_connectivity_tiles_section(self, y: float, x: float, width: float): tile_rows = self._connectivity_tile_grid.get_row_count(len(self._connectivity_tile_grid.tiles), available_width=width) tile_gaps = self._connectivity_tile_grid.get_internal_gap_height(len(self._connectivity_tile_grid.tiles), available_width=width) - tile_h = tile_rows * 96 + tile_gaps - group_rect = rl.Rectangle(x, y, width, tile_h) - draw_list_group_shell(group_rect, style=PANEL_STYLE) + tiles_content_h = tile_rows * 130 + tile_gaps + + draw_list_group_shell(rl.Rectangle(x, y, width, tiles_content_h + 24), style=PANEL_STYLE) self._connectivity_tile_grid.set_parent_rect(self._scroll_rect) - self._connectivity_tile_grid.render(rl.Rectangle(x, y, width, tile_h)) + self._connectivity_tile_grid.render(rl.Rectangle(x + 12, y + 12, width - 24, tiles_content_h)) def _draw_slider_section(self, y: float, x: float, width: float, title: str, keys: list[str]) -> float: draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), title, style=PANEL_STYLE)