From 1fb31b2e126bb80672ff7af36ebc4465ed4adb1b Mon Sep 17 00:00:00 2001 From: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Date: Thu, 7 May 2026 19:57:18 -0400 Subject: [PATCH] BigUI WIP: Cleanup/uniformity --- .../settings/starpilot/driving_model.py | 69 +++++----- .../ui/layouts/settings/starpilot/maps.py | 26 ++-- .../settings/starpilot/system_settings.py | 119 +++++++++--------- .../ui/layouts/settings/starpilot/vehicle.py | 110 ++++++++-------- 4 files changed, 153 insertions(+), 171 deletions(-) diff --git a/selfdrive/ui/layouts/settings/starpilot/driving_model.py b/selfdrive/ui/layouts/settings/starpilot/driving_model.py index cd96cca0c2..6cb623d75b 100644 --- a/selfdrive/ui/layouts/settings/starpilot/driving_model.py +++ b/selfdrive/ui/layouts/settings/starpilot/driving_model.py @@ -108,10 +108,7 @@ class DrivingModelManagerView(Widget): self._scroll_offset = 0.0 self._pressed_target: str | None = None self._can_click = True - self._row_rects: dict[str, rl.Rectangle] = {} - self._action_rects: dict[str, rl.Rectangle] = {} - self._utility_rects: dict[str, rl.Rectangle] = {} - self._menu_sub_rects: dict[str, rl.Rectangle] = {} + self._interactive_rects: dict[str, rl.Rectangle] = {} self._confirm_key: str | None = None self._confirm_until = 0.0 self._transition_starts: dict[str, tuple[float, float]] = {} @@ -202,36 +199,26 @@ class DrivingModelManagerView(Widget): self._can_click = True def _handle_mouse_event(self, mouse_event: MouseEvent): - del mouse_event if not self._scroll_panel.is_touch_valid(): self._can_click = False + return + if self._pressed_target is not None and self._target_at(mouse_event.pos) != self._pressed_target: + self._pressed_target = None def _handle_mouse_release(self, mouse_pos: MousePos): - target = self._target_at(mouse_pos) + target = self._target_at(mouse_pos) if self._scroll_panel.is_touch_valid() else None if self._pressed_target is not None and self._pressed_target == target and self._can_click: self._activate_target(target) self._pressed_target = None + self._can_click = True def _target_at(self, mouse_pos: MousePos) -> str | None: - for sub_key, rect in self._menu_sub_rects.items(): - if _point_hits(mouse_pos, rect, self._scroll_rect, pad_x=6, pad_y=6): - return f"menu:{sub_key}" - - for key, rect in self._action_rects.items(): - visible_rect = rl.get_collision_rec(rect, self._scroll_rect) - if visible_rect.width > 0 and visible_rect.height > 0 and rl.check_collision_point_rec(mouse_pos, visible_rect): - return f"action:{key}" - - for name, rect in self._utility_rects.items(): - visible_rect = rl.get_collision_rec(rect, self._scroll_rect) - if visible_rect.width > 0 and visible_rect.height > 0 and rl.check_collision_point_rec(mouse_pos, visible_rect): - return f"utility:{name}" - - for key, rect in self._row_rects.items(): - visible_rect = rl.get_collision_rec(rect, self._scroll_rect) - if visible_rect.width > 0 and visible_rect.height > 0 and rl.check_collision_point_rec(mouse_pos, visible_rect): - return f"row:{key}" - + for prefix in ("menu:", "action:", "utility:", "row:"): + for target_id, rect in self._interactive_rects.items(): + if target_id.startswith(prefix): + pad_y = 6 if prefix == "menu:" else 0 + if _point_hits(mouse_pos, rect, self._scroll_rect, pad_x=6, pad_y=pad_y): + return target_id return None def _activate_target(self, target: str | None): @@ -291,10 +278,7 @@ class DrivingModelManagerView(Widget): def _render(self, rect: rl.Rectangle): self.set_rect(rect) - self._row_rects.clear() - self._action_rects.clear() - self._utility_rects.clear() - self._menu_sub_rects.clear() + self._interactive_rects.clear() frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE) self._shell_rect = frame.shell @@ -389,7 +373,7 @@ class DrivingModelManagerView(Widget): def _draw_empty_state(self, rect: rl.Rectangle): draw_empty_state_card( - rl.Rectangle(rect.x, rect.y, rect.width - AETHER_LIST_METRICS.content_right_gutter, rect.height), + rl.Rectangle(rect.x, rect.y, rect.width, rect.height), self._controller.empty_state_title(), self._controller.empty_state_body(), title_size=32, @@ -401,17 +385,20 @@ class DrivingModelManagerView(Widget): ) def _draw_model_section(self, x: float, y: float, width: float, title: str, entries: list[ModelCatalogEntry]) -> float: - draw_section_header(rl.Rectangle(x, y, width - AETHER_LIST_METRICS.content_right_gutter, SECTION_HEADER_HEIGHT), title, style=PANEL_STYLE) + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), title, style=PANEL_STYLE) y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + group_rect = rl.Rectangle(x, y, width, len(entries) * ROW_HEIGHT) + draw_list_group_shell(group_rect, style=PANEL_STYLE) + for index, entry in enumerate(entries): - row_rect = rl.Rectangle(x, y + index * ROW_HEIGHT, width - AETHER_LIST_METRICS.content_right_gutter, ROW_HEIGHT) + row_rect = rl.Rectangle(x, y + index * ROW_HEIGHT, width, ROW_HEIGHT) self._draw_model_row(row_rect, entry, is_last=index == len(entries) - 1) return y + len(entries) * ROW_HEIGHT def _draw_model_row(self, rect: rl.Rectangle, entry: ModelCatalogEntry, is_last: bool): mouse_pos = gui_app.last_mouse_event.pos - row_hovered = rl.check_collision_point_rec(mouse_pos, rect) + row_hovered = bool(_point_hits(mouse_pos, rect, self._scroll_rect, pad_x=6, pad_y=0)) target_key = f"row:{entry.key}" pressed = self._pressed_target == target_key current = self._controller.is_current_model(entry.key) @@ -446,7 +433,7 @@ class DrivingModelManagerView(Widget): info_rect = rl.Rectangle(draw_rect.x + 24, draw_rect.y + 18, draw_rect.width - ACTION_WIDTH - 42, draw_rect.height - 36) row_touchable = entry.installed and not self._controller._params.get_bool("ModelRandomizer") if row_touchable: - self._row_rects[entry.key] = draw_rect + self._interactive_rects[f"row:{entry.key}"] = draw_rect self._draw_model_info(info_rect, entry, current) @@ -456,10 +443,10 @@ class DrivingModelManagerView(Widget): elif not removable: self._draw_protected_action(action_rect) else: - self._action_rects[entry.key] = action_rect + self._interactive_rects[f"action:{entry.key}"] = action_rect self._draw_menu_action(action_rect, is_menu_open, entry) else: - self._action_rects[entry.key] = action_rect + self._interactive_rects[f"action:{entry.key}"] = action_rect if downloading: self._draw_downloading_action(action_rect, self._controller.download_progress_text()) else: @@ -548,8 +535,8 @@ class DrivingModelManagerView(Widget): delete_rect = rl.Rectangle(rect.x + 10, start_y, rect.width - 20, btn_h) fav_rect = rl.Rectangle(rect.x + 10, start_y + btn_h + gap, rect.width - 20, btn_h) - self._menu_sub_rects[f"{entry.key}:delete"] = delete_rect - self._menu_sub_rects[f"{entry.key}:favorite"] = fav_rect + self._interactive_rects[f"menu:{entry.key}:delete"] = delete_rect + self._interactive_rects[f"menu:{entry.key}:favorite"] = fav_rect # Delete button draw_action_pill(delete_rect, tr("Delete"), AetherListColors.DANGER_SOFT, rl.Color(AetherListColors.DANGER.r, AetherListColors.DANGER.g, AetherListColors.DANGER.b, min(AetherListColors.DANGER.a, 70)), AetherListColors.DANGER) @@ -571,7 +558,7 @@ class DrivingModelManagerView(Widget): AetherChip(tr("Protected"), rl.Color(255, 255, 255, 10), AetherListColors.MUTED, AetherListColors.SUBTEXT, font_size=18).render(chip_rect) def _draw_utility_section(self, x: float, y: float, width: float, rows: list[dict]): - content_w = width - AETHER_LIST_METRICS.content_right_gutter + content_w = width draw_section_header(rl.Rectangle(x, y, content_w, SECTION_HEADER_HEIGHT), tr("Automation and Tuning"), style=PANEL_STYLE) y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP @@ -584,9 +571,9 @@ class DrivingModelManagerView(Widget): def _draw_utility_row(self, rect: rl.Rectangle, row: dict, is_last: bool): mouse_pos = gui_app.last_mouse_event.pos - hovered = rl.check_collision_point_rec(mouse_pos, rect) + hovered = bool(_point_hits(mouse_pos, rect, self._scroll_rect, pad_x=6, pad_y=0)) pressed = self._pressed_target == f"utility:{row['id']}" - self._utility_rects[row["id"]] = rect + self._interactive_rects[f"utility:{row['id']}"] = rect draw_settings_list_row( rect, title=row["title"], diff --git a/selfdrive/ui/layouts/settings/starpilot/maps.py b/selfdrive/ui/layouts/settings/starpilot/maps.py index 439c30a94a..13d7105fd0 100644 --- a/selfdrive/ui/layouts/settings/starpilot/maps.py +++ b/selfdrive/ui/layouts/settings/starpilot/maps.py @@ -85,7 +85,7 @@ STATUS_REMOVE_HEIGHT = 40 STATUS_METRIC_GAP = 18 STATUS_SELECTION_CHIP_HEIGHT = 30 MAPS_TILE_GREEN = rl.Color(16, 185, 129, 255) -MAPS_PANEL_STYLE = replace( +PANEL_STYLE = replace( DEFAULT_PANEL_STYLE, accent=MAPS_TILE_GREEN, current_fill=rl.Color(16, 185, 129, 16), @@ -180,7 +180,7 @@ class MapStatusCard(Widget): self._controller._on_remove() def _render(self, rect: rl.Rectangle): - draw_soft_card(rect, MAPS_PANEL_STYLE.surface_fill, MAPS_PANEL_STYLE.surface_border) + draw_soft_card(rect, PANEL_STYLE.surface_fill, PANEL_STYLE.surface_border) inset = STATUS_CARD_INSET content_x = rect.x + inset @@ -233,7 +233,7 @@ class MapStatusCard(Widget): (tr("Last Updated"), self._controller._last_updated_text()), ], gap=STATUS_METRIC_GAP, - style=MAPS_PANEL_STYLE, + style=PANEL_STYLE, label_top_offset=0, value_top_offset=14, divider_top_offset=2, @@ -247,7 +247,7 @@ class MapStatusCard(Widget): (tr("Last Updated"), self._controller._last_updated_text()), ], gap=STATUS_METRIC_GAP, - style=MAPS_PANEL_STYLE, + style=PANEL_STYLE, label_top_offset=0, value_top_offset=14, divider_top_offset=2, @@ -361,7 +361,7 @@ class MapBrowserCard(Widget): hovered=hovered, pressed=pressed, title_size=28, - style=MAPS_PANEL_STYLE, + style=PANEL_STYLE, ) def _row_height(self, count: int, row_height: float) -> float: @@ -402,7 +402,7 @@ class MapBrowserCard(Widget): title_size=24, subtitle_size=17, show_underline=True, - style=MAPS_PANEL_STYLE, + style=PANEL_STYLE, ) def _render_empty_state(self, rect: rl.Rectangle, title: str, body: str): @@ -416,7 +416,7 @@ class MapBrowserCard(Widget): title_top_padding=24, body_height=48, border=rl.Color(255, 255, 255, 10), - style=MAPS_PANEL_STYLE, + style=PANEL_STYLE, ) def _render_region_rows(self, rect: rl.Rectangle, regions: list[dict]): @@ -451,9 +451,9 @@ class MapBrowserCard(Widget): action_pill_width=132 if selected else 108, title_size=34, subtitle_size=22, - row_separator=MAPS_PANEL_STYLE.divider_color, - current_bg=MAPS_PANEL_STYLE.current_fill, - current_border=MAPS_PANEL_STYLE.current_border, + row_separator=PANEL_STYLE.divider_color, + current_bg=PANEL_STYLE.current_fill, + current_border=PANEL_STYLE.current_border, action_fill=rl.Color(94, 168, 130, 18) if selected else rl.Color(255, 255, 255, 8), action_border=rl.Color(94, 168, 130, 38) if selected else rl.Color(255, 255, 255, 24), action_text_color=AetherListColors.HEADER, @@ -463,7 +463,7 @@ class MapBrowserCard(Widget): return self._controller._browse_regions_for_active_group() def _render_section_header(self, rect: rl.Rectangle, title: str, *, count_text: str | None = None): - draw_section_header(rect, title, trailing_text=count_text or "", title_size=28, trailing_size=22, style=MAPS_PANEL_STYLE) + draw_section_header(rect, title, trailing_text=count_text or "", title_size=28, trailing_size=22, style=PANEL_STYLE) def _measure_height(self, width: float) -> float: if self._controller._showing_source_picker(): @@ -481,7 +481,7 @@ class MapBrowserCard(Widget): self.set_rect(rect) if not self._touch_valid(): self._pressed_target = None - draw_soft_card(rect, MAPS_PANEL_STYLE.surface_fill, MAPS_PANEL_STYLE.surface_border) + draw_soft_card(rect, PANEL_STYLE.surface_fill, PANEL_STYLE.surface_border) self._source_rects.clear() self._context_tab_rects.clear() self._region_row_rects.clear() @@ -1130,7 +1130,7 @@ class StarPilotMapsLayout(StarPilotPanel): def _render(self, rect: rl.Rectangle): self.set_rect(rect) - frame, scroll_rect, content_width = init_list_panel(rect, MAPS_PANEL_STYLE, MAPS_METRICS) + frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE, MAPS_METRICS) hdr = frame.header draw_settings_panel_header(hdr, tr("Map Data"), tr("Use offline maps for speed-limit control and keep only the regions you need."), diff --git a/selfdrive/ui/layouts/settings/starpilot/system_settings.py b/selfdrive/ui/layouts/settings/starpilot/system_settings.py index 8da407ce33..74e0b0ef13 100644 --- a/selfdrive/ui/layouts/settings/starpilot/system_settings.py +++ b/selfdrive/ui/layouts/settings/starpilot/system_settings.py @@ -12,7 +12,7 @@ import pyray as rl from openpilot.system.hardware import HARDWARE from openpilot.system.ui.lib.application import gui_app, FontWeight, MouseEvent, MousePos -from openpilot.system.ui.lib.multilang import tr +from openpilot.system.ui.lib.multilang import tr, tr_noop from openpilot.system.ui.lib.scroll_panel2 import GuiScrollPanel2 from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.widgets import DialogResult, Widget @@ -65,17 +65,25 @@ EXCLUDED_KEYS = { } REPORT_CATEGORIES = [ - "Acceleration feels harsh or jerky", - "An alert was unclear and I'm not sure what it meant", - "Braking is too sudden or uncomfortable", - "I'm not sure if this is normal or a bug:", - "My steering wheel buttons aren't working", - "openpilot disengages when I don't expect it", - "openpilot feels sluggish or slow to respond", - "Something else (please describe)", + tr_noop("Acceleration feels harsh or jerky"), + tr_noop("An alert was unclear and I'm not sure what it meant"), + tr_noop("Braking is too sudden or uncomfortable"), + tr_noop("I'm not sure if this is normal or a bug:"), + tr_noop("My steering wheel buttons aren't working"), + tr_noop("openpilot disengages when I don't expect it"), + tr_noop("openpilot feels sluggish or slow to respond"), + tr_noop("Something else (please describe)"), ] +SECTION_GAP = AETHER_LIST_METRICS.section_gap +SECTION_HEADER_HEIGHT = AETHER_LIST_METRICS.section_header_height +SECTION_HEADER_GAP = AETHER_LIST_METRICS.section_header_gap +ROW_HEIGHT = AETHER_LIST_METRICS.row_height +FADE_HEIGHT = AETHER_LIST_METRICS.fade_height +PANEL_STYLE = DEFAULT_PANEL_STYLE + + class SystemSettingsManagerView(Widget): HEADER_SUBTITLE_HEIGHT = 24 HEADER_SUMMARY_GAP = 12 @@ -83,18 +91,11 @@ class SystemSettingsManagerView(Widget): TAB_HEIGHT = 56 TAB_GAP = 10 TAB_BOTTOM_GAP = 18 - SECTION_GAP = AETHER_LIST_METRICS.section_gap - SECTION_HEADER_HEIGHT = AETHER_LIST_METRICS.section_header_height - SECTION_HEADER_GAP = AETHER_LIST_METRICS.section_header_gap - ROW_HEIGHT = AETHER_LIST_METRICS.row_height - FADE_HEIGHT = AETHER_LIST_METRICS.fade_height COLUMN_GAP = 22 TWO_COLUMN_BREAKPOINT = 1180 ACTION_PILL_WIDTH = 132 DANGER_PILL_WIDTH = 112 - PANEL_STYLE = DEFAULT_PANEL_STYLE - def __init__(self, controller: "StarPilotSystemLayout"): super().__init__() self._controller = controller @@ -216,8 +217,8 @@ class SystemSettingsManagerView(Widget): presets=spec.get("presets", []), is_active=lambda key=key: self._active_adjustor_key == key, set_active=lambda active, key=key: self._set_active_adjustor(key, active), - style=self.PANEL_STYLE, - color=self.PANEL_STYLE.accent, + style=PANEL_STYLE, + color=PANEL_STYLE.accent, ) ) adjustor.set_touch_valid_callback(lambda adjustor=adjustor: self._scroll_panel.is_touch_valid() or adjustor.is_interacting) @@ -361,7 +362,7 @@ class SystemSettingsManagerView(Widget): def _stacked_section_height(self, sections: list[float]) -> float: if not sections: return 0.0 - return max(0.0, sum(sections) - self.SECTION_GAP) + return sum(sections) + SECTION_GAP * (len(sections) - 1) def _uses_two_columns(self, width: float) -> bool: return width >= self.TWO_COLUMN_BREAKPOINT @@ -490,7 +491,7 @@ class SystemSettingsManagerView(Widget): def _render(self, rect: rl.Rectangle): self.set_rect(rect) - frame, scroll_rect, content_width = init_list_panel(rect, self.PANEL_STYLE) + frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE) self._scroll_rect = scroll_rect self._drive_mode_control.set_parent_rect(frame.header) @@ -507,7 +508,7 @@ class SystemSettingsManagerView(Widget): if self._content_height > scroll_rect.height: self._scrollbar.render(scroll_rect, self._content_height, self._scroll_offset) - draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, AetherListColors.PANEL_BG, fade_height=self.FADE_HEIGHT) + draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, AetherListColors.PANEL_BG, fade_height=FADE_HEIGHT) def _draw_header(self, rect: rl.Rectangle): draw_settings_panel_header(rect, tr("System Settings"), @@ -519,7 +520,7 @@ class SystemSettingsManagerView(Widget): self._draw_summary_card(summary_rect) def _draw_summary_card(self, rect: rl.Rectangle): - draw_soft_card(rect, self.PANEL_STYLE.surface_fill, self.PANEL_STYLE.surface_border) + draw_soft_card(rect, PANEL_STYLE.surface_fill, PANEL_STYLE.surface_border) inset = 18 left_x = rect.x + inset left_w = rect.width * 0.40 @@ -560,7 +561,7 @@ class SystemSettingsManagerView(Widget): def _measure_active_tab_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)) - backups_h = self._section_block_height(self._section_height(2, self.ROW_HEIGHT)) + backups_h = self._section_block_height(self._section_height(2, ROW_HEIGHT)) maintenance_h = self._section_block_height(self._maintenance_section_content_height()) if self._active_tab_key == "basics": if self._uses_two_columns(width): @@ -568,7 +569,7 @@ class SystemSettingsManagerView(Widget): return self._stacked_section_height([display_h, power_h]) if self._active_tab_key == "connectivity": - group_heights = [self._section_block_height(self._section_height(len(self._toggle_defs_for_group(group)), self.ROW_HEIGHT)) for group in self._toggle_groups] + group_heights = [self._section_block_height(self._section_height(len(self._toggle_defs_for_group(group)), ROW_HEIGHT)) for group in self._toggle_groups] if self._uses_two_columns(width): return max(group_heights) return self._stacked_section_height(group_heights) @@ -578,7 +579,7 @@ class SystemSettingsManagerView(Widget): return self._stacked_section_height([backups_h, maintenance_h]) def _section_block_height(self, content_height: float) -> float: - return self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP + content_height + self.SECTION_GAP + return SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + content_height def _slider_section_height(self, keys: list[str], width: float) -> float: total = 0.0 @@ -588,8 +589,8 @@ class SystemSettingsManagerView(Widget): return total def _maintenance_section_content_height(self) -> float: - support_h = self._section_height(len(self._support_rows), self.ROW_HEIGHT) - danger_h = self._section_height(len(self._danger_rows), self.ROW_HEIGHT) + support_h = self._section_height(len(self._support_rows), ROW_HEIGHT) + danger_h = self._section_height(len(self._danger_rows), ROW_HEIGHT) return support_h + 12 + 30 + danger_h def _draw_scroll_content(self, rect: rl.Rectangle, width: float): @@ -624,7 +625,7 @@ class SystemSettingsManagerView(Widget): title_size=26, subtitle_size=17, show_underline=True, - style=self.PANEL_STYLE, + style=PANEL_STYLE, ) def _draw_basics_tab(self, y: float, x: float, width: float): @@ -634,6 +635,7 @@ class SystemSettingsManagerView(Widget): self._draw_slider_section(y, x + column_w + self.COLUMN_GAP, column_w, tr("Power"), self._power_slider_keys) return y = self._draw_slider_section(y, x, width, tr("Display"), self._display_slider_keys) + y += SECTION_GAP self._draw_slider_section(y, x, width, tr("Power"), self._power_slider_keys) def _draw_connectivity_tab(self, y: float, x: float, width: float): @@ -643,8 +645,10 @@ class SystemSettingsManagerView(Widget): self._draw_toggle_group_section(y, x + column_w + self.COLUMN_GAP, column_w, self._toggle_groups[1]) return current_y = y - for group in self._toggle_groups: + for i, group in enumerate(self._toggle_groups): current_y = self._draw_toggle_group_section(current_y, x, width, group) + if i < len(self._toggle_groups) - 1: + current_y += SECTION_GAP def _draw_care_tab(self, y: float, x: float, width: float): if self._uses_two_columns(width): @@ -653,17 +657,18 @@ class SystemSettingsManagerView(Widget): self._draw_maintenance_section(y, x + column_w + self.COLUMN_GAP, column_w) return y = self._draw_backups_section(y, x, width) + y += SECTION_GAP self._draw_maintenance_section(y, x, width) 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, self.SECTION_HEADER_HEIGHT), title, style=self.PANEL_STYLE) - y += self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), title, style=PANEL_STYLE) + y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP group_rect = rl.Rectangle(x, y, width, self._slider_section_height(keys, width)) - draw_list_group_shell(group_rect) + draw_list_group_shell(group_rect, style=PANEL_STYLE) current_y = group_rect.y for index, key in enumerate(keys): current_y = self._draw_slider_row(rl.Rectangle(group_rect.x, current_y, group_rect.width, 0), key, is_last=index == len(keys) - 1) - return y + group_rect.height + self.SECTION_GAP + return y + group_rect.height def _draw_slider_row(self, rect: rl.Rectangle, key: str, is_last: bool) -> float: adjustor = self._adjustor_rows[key] @@ -687,13 +692,13 @@ class SystemSettingsManagerView(Widget): def _draw_toggle_group_section(self, y: float, x: float, width: float, group: dict) -> float: toggles = self._toggle_defs_for_group(group) trailing_text = tr("{} toggles").format(len(toggles)) - draw_section_header(rl.Rectangle(x, y, width, self.SECTION_HEADER_HEIGHT), group["title"], trailing_text=trailing_text, style=self.PANEL_STYLE) - y += self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP - toggle_rect = rl.Rectangle(x, y, width, self._section_height(len(toggles), self.ROW_HEIGHT)) - draw_list_group_shell(toggle_rect) + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), group["title"], trailing_text=trailing_text, style=PANEL_STYLE) + y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + toggle_rect = rl.Rectangle(x, y, width, self._section_height(len(toggles), ROW_HEIGHT)) + draw_list_group_shell(toggle_rect, style=PANEL_STYLE) for index, toggle_def in enumerate(toggles): - self._draw_toggle_row(rl.Rectangle(toggle_rect.x, toggle_rect.y + index * self.ROW_HEIGHT, toggle_rect.width, self.ROW_HEIGHT), toggle_def, is_last=index == len(toggles) - 1) - return y + toggle_rect.height + self.SECTION_GAP + self._draw_toggle_row(rl.Rectangle(toggle_rect.x, toggle_rect.y + index * ROW_HEIGHT, toggle_rect.width, ROW_HEIGHT), toggle_def, is_last=index == len(toggles) - 1) + return y + toggle_rect.height def _draw_toggle_row(self, rect: rl.Rectangle, toggle_def: dict, is_last: bool): target_id = f"toggle:{toggle_def['id']}" @@ -712,18 +717,18 @@ class SystemSettingsManagerView(Widget): show_chevron=False, title_size=34, subtitle_size=22, - style=self.PANEL_STYLE, + style=PANEL_STYLE, ) def _draw_backups_section(self, y: float, x: float, width: float) -> float: - draw_section_header(rl.Rectangle(x, y, width, self.SECTION_HEADER_HEIGHT), tr("Backups"), trailing_text=self._controller.backup_status_text(), style=self.PANEL_STYLE) - y += self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), tr("Backups"), trailing_text=self._controller.backup_status_text(), style=PANEL_STYLE) + y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP - summary_rect = rl.Rectangle(x, y, width, self.ROW_HEIGHT * 2) - draw_list_group_shell(summary_rect) - self._draw_backup_manager_row(rl.Rectangle(summary_rect.x, summary_rect.y, summary_rect.width, self.ROW_HEIGHT), "system", is_last=False) - self._draw_backup_manager_row(rl.Rectangle(summary_rect.x, summary_rect.y + self.ROW_HEIGHT, summary_rect.width, self.ROW_HEIGHT), "toggle", is_last=True) - return y + summary_rect.height + self.SECTION_GAP + summary_rect = rl.Rectangle(x, y, width, ROW_HEIGHT * 2) + draw_list_group_shell(summary_rect, style=PANEL_STYLE) + self._draw_backup_manager_row(rl.Rectangle(summary_rect.x, summary_rect.y, summary_rect.width, ROW_HEIGHT), "system", is_last=False) + self._draw_backup_manager_row(rl.Rectangle(summary_rect.x, summary_rect.y + ROW_HEIGHT, summary_rect.width, ROW_HEIGHT), "toggle", is_last=True) + return y + summary_rect.height def _draw_backup_manager_row(self, rect: rl.Rectangle, backup_kind: str, is_last: bool): target_id = f"backup:{backup_kind}" @@ -752,20 +757,20 @@ class SystemSettingsManagerView(Widget): title_size=34, subtitle_size=22, action_text_size=18, - row_separator=self.PANEL_STYLE.divider_color, + row_separator=PANEL_STYLE.divider_color, action_fill=AetherListColors.CURRENT_BG, action_border=rl.Color(89, 116, 151, 42), action_text_color=AetherListColors.HEADER, ) def _draw_maintenance_section(self, y: float, x: float, width: float): - draw_section_header(rl.Rectangle(x, y, width, self.SECTION_HEADER_HEIGHT), tr("Support & Maintenance"), style=self.PANEL_STYLE) - y += self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), tr("Support & Maintenance"), style=PANEL_STYLE) + y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP - support_rect = rl.Rectangle(x, y, width, self._section_height(len(self._support_rows), self.ROW_HEIGHT)) - draw_list_group_shell(support_rect) + support_rect = rl.Rectangle(x, y, width, self._section_height(len(self._support_rows), ROW_HEIGHT)) + draw_list_group_shell(support_rect, style=PANEL_STYLE) for index, row in enumerate(self._support_rows): - row_rect = rl.Rectangle(support_rect.x, support_rect.y + index * self.ROW_HEIGHT, support_rect.width, self.ROW_HEIGHT) + row_rect = rl.Rectangle(support_rect.x, support_rect.y + index * ROW_HEIGHT, support_rect.width, ROW_HEIGHT) self._draw_action_row(row_rect, row, is_last=index == len(self._support_rows) - 1) y += support_rect.height + 12 @@ -773,10 +778,10 @@ class SystemSettingsManagerView(Widget): gui_label(danger_title_rect, tr("Danger Zone"), 20, AetherListColors.DANGER, FontWeight.MEDIUM) y += 30 - danger_rect = rl.Rectangle(x, y, width, self._section_height(len(self._danger_rows), self.ROW_HEIGHT)) - draw_list_group_shell(danger_rect, fill=rl.Color(173, 78, 90, 10), border=rl.Color(173, 78, 90, 30)) + danger_rect = rl.Rectangle(x, y, width, self._section_height(len(self._danger_rows), ROW_HEIGHT)) + draw_list_group_shell(danger_rect, fill=rl.Color(173, 78, 90, 10), border=rl.Color(173, 78, 90, 30), style=PANEL_STYLE) for index, row in enumerate(self._danger_rows): - row_rect = rl.Rectangle(danger_rect.x, danger_rect.y + index * self.ROW_HEIGHT, danger_rect.width, self.ROW_HEIGHT) + row_rect = rl.Rectangle(danger_rect.x, danger_rect.y + index * ROW_HEIGHT, danger_rect.width, ROW_HEIGHT) self._draw_action_row(row_rect, row, is_last=index == len(self._danger_rows) - 1, danger=True) def _draw_action_row(self, rect: rl.Rectangle, row: dict, is_last: bool, *, danger: bool = False): @@ -800,7 +805,7 @@ class SystemSettingsManagerView(Widget): title_size=34, subtitle_size=22, action_text_size=18, - row_separator=self.PANEL_STYLE.divider_color, + row_separator=PANEL_STYLE.divider_color, action_fill=action_fill, action_border=action_border, action_text_color=action_text_color, diff --git a/selfdrive/ui/layouts/settings/starpilot/vehicle.py b/selfdrive/ui/layouts/settings/starpilot/vehicle.py index 4e24773e4e..acb3127566 100644 --- a/selfdrive/ui/layouts/settings/starpilot/vehicle.py +++ b/selfdrive/ui/layouts/settings/starpilot/vehicle.py @@ -10,7 +10,7 @@ from openpilot.system.ui.widgets import DialogResult, Widget from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog from openpilot.system.ui.widgets.label import gui_label from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog -from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanel +from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import _SettingsPage from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import ( AETHER_LIST_METRICS, AetherListColors, @@ -38,15 +38,15 @@ from openpilot.selfdrive.ui.mici.layouts.settings.fingerprint_catalog import ( ACTION_OPTIONS = [ - {"id": 0, "name": "No Action"}, - {"id": 1, "name": "Change Personality", "requires_longitudinal": True}, - {"id": 2, "name": "Force Coast", "requires_longitudinal": True}, - {"id": 3, "name": "Pause Steering"}, - {"id": 4, "name": "Pause Accel/Brake", "requires_longitudinal": True}, - {"id": 5, "name": "Toggle Experimental", "requires_longitudinal": True}, - {"id": 6, "name": "Toggle Traffic", "requires_longitudinal": True}, - {"id": 7, "name": "Toggle Switchback"}, - {"id": 8, "name": "Create Bookmark"}, + {"id": 0, "name": tr_noop("No Action")}, + {"id": 1, "name": tr_noop("Change Personality"), "requires_longitudinal": True}, + {"id": 2, "name": tr_noop("Force Coast"), "requires_longitudinal": True}, + {"id": 3, "name": tr_noop("Pause Steering")}, + {"id": 4, "name": tr_noop("Pause Accel/Brake"), "requires_longitudinal": True}, + {"id": 5, "name": tr_noop("Toggle Experimental"), "requires_longitudinal": True}, + {"id": 6, "name": tr_noop("Toggle Traffic"), "requires_longitudinal": True}, + {"id": 7, "name": tr_noop("Toggle Switchback")}, + {"id": 8, "name": tr_noop("Create Bookmark")}, ] ACTION_NAMES = [o["name"] for o in ACTION_OPTIONS] ACTION_IDS = {o["name"]: o["id"] for o in ACTION_OPTIONS} @@ -60,6 +60,14 @@ def _lock_doors_timer_labels(): return labels +SECTION_GAP = AETHER_LIST_METRICS.section_gap +SECTION_HEADER_HEIGHT = AETHER_LIST_METRICS.section_header_height +SECTION_HEADER_GAP = AETHER_LIST_METRICS.section_header_gap +ROW_HEIGHT = AETHER_LIST_METRICS.row_height +FADE_HEIGHT = AETHER_LIST_METRICS.fade_height +PANEL_STYLE = DEFAULT_PANEL_STYLE + + class VehicleSettingsManagerView(Widget): HEADER_SUBTITLE_HEIGHT = 24 HEADER_SUMMARY_GAP = 12 @@ -67,15 +75,8 @@ class VehicleSettingsManagerView(Widget): TAB_HEIGHT = 56 TAB_GAP = 10 TAB_BOTTOM_GAP = 18 - SECTION_GAP = AETHER_LIST_METRICS.section_gap - SECTION_HEADER_HEIGHT = AETHER_LIST_METRICS.section_header_height - SECTION_HEADER_GAP = AETHER_LIST_METRICS.section_header_gap - ROW_HEIGHT = AETHER_LIST_METRICS.row_height - FADE_HEIGHT = AETHER_LIST_METRICS.fade_height - COLUMN_GAP = 22 TWO_COLUMN_BREAKPOINT = 1180 - - PANEL_STYLE = DEFAULT_PANEL_STYLE + COLUMN_GAP = 22 def __init__(self, controller: "StarPilotVehicleSettingsLayout"): super().__init__() @@ -109,12 +110,12 @@ class VehicleSettingsManagerView(Widget): def _section_block_height(self, content_height: float) -> float: if content_height <= 0: return 0.0 - return self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP + content_height + self.SECTION_GAP + return SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + content_height def _stacked_section_height(self, sections: list[float]) -> float: if not sections: return 0.0 - return max(0.0, sum(sections) - self.SECTION_GAP) + return max(0.0, sum(sections) - SECTION_GAP) def _interactive_state(self, target_id: str, rect: rl.Rectangle, *, pad_y: float = 0) -> tuple[bool, bool]: self._interactive_rects[target_id] = rect @@ -194,9 +195,8 @@ class VehicleSettingsManagerView(Widget): def _render(self, rect: rl.Rectangle): self.set_rect(rect) - self._interactive_rects.clear() - frame, scroll_rect, content_width = init_list_panel(rect, self.PANEL_STYLE) + frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE) self._shell_rect = frame.shell self._scroll_rect = scroll_rect @@ -213,7 +213,7 @@ class VehicleSettingsManagerView(Widget): if self._content_height > scroll_rect.height: self._scrollbar.render(scroll_rect, self._content_height, self._scroll_offset) - draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, AetherListColors.PANEL_BG, fade_height=self.FADE_HEIGHT) + draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, AetherListColors.PANEL_BG, fade_height=FADE_HEIGHT) def _draw_header(self, rect: rl.Rectangle): draw_settings_panel_header(rect, tr("Vehicle Settings"), @@ -225,7 +225,7 @@ class VehicleSettingsManagerView(Widget): self._draw_summary_card(summary_rect) def _draw_summary_card(self, rect: rl.Rectangle): - draw_soft_card(rect, self.PANEL_STYLE.surface_fill, self.PANEL_STYLE.surface_border) + draw_soft_card(rect, PANEL_STYLE.surface_fill, PANEL_STYLE.surface_border) inset = 18 left_x = rect.x + inset left_w = rect.width * 0.40 @@ -252,7 +252,7 @@ class VehicleSettingsManagerView(Widget): draw_metric_strip( rl.Rectangle(left_x, rect.y + 72, max(240.0, rect.width * 0.38), 30), metrics, - style=self.PANEL_STYLE, + style=PANEL_STYLE, label_top_offset=0, value_top_offset=14, divider_top_offset=2, @@ -286,19 +286,19 @@ class VehicleSettingsManagerView(Widget): def _measure_active_tab_height(self, width: float) -> float: if self._active_tab_key == "identity": - return self._section_block_height(self._section_height(3, self.ROW_HEIGHT)) + return self._section_block_height(self._section_height(3, ROW_HEIGHT)) if self._active_tab_key == "features": rows = self._build_driving_rows() if self._uses_two_columns(width): max_per_col = (len(rows) + 1) // 2 - return self._section_block_height(self._section_height(max_per_col, self.ROW_HEIGHT)) - return self._section_block_height(self._section_height(len(rows), self.ROW_HEIGHT)) + return self._section_block_height(self._section_height(max_per_col, ROW_HEIGHT)) + return self._section_block_height(self._section_height(len(rows), ROW_HEIGHT)) if self._active_tab_key == "controls": rows = self._build_steering_rows() if self._uses_two_columns(width): max_per_col = (len(rows) + 1) // 2 - return self._section_block_height(self._section_height(max_per_col, self.ROW_HEIGHT)) - return self._section_block_height(self._section_height(len(rows), self.ROW_HEIGHT)) + return self._section_block_height(self._section_height(max_per_col, ROW_HEIGHT)) + return self._section_block_height(self._section_height(len(rows), ROW_HEIGHT)) return 0 def _draw_scroll_content(self, rect: rl.Rectangle, width: float): @@ -333,7 +333,7 @@ class VehicleSettingsManagerView(Widget): title_size=26, subtitle_size=17, show_underline=True, - style=self.PANEL_STYLE, + style=PANEL_STYLE, ) def _draw_identity_tab(self, y: float, x: float, width: float): @@ -346,12 +346,12 @@ class VehicleSettingsManagerView(Widget): "subtitle": tr("Manually select vehicle instead of auto-detecting."), "get_state": lambda: self._controller._params.get_bool("ForceFingerprint")}, ] - draw_section_header(rl.Rectangle(x, y, width, self.SECTION_HEADER_HEIGHT), tr("Vehicle Identity"), style=self.PANEL_STYLE) - y += self.SECTION_HEADER_HEIGHT + self.SECTION_HEADER_GAP - container_rect = rl.Rectangle(x, y, width, len(rows) * self.ROW_HEIGHT) - draw_list_group_shell(container_rect) + draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), tr("Vehicle Identity"), style=PANEL_STYLE) + y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP + container_rect = rl.Rectangle(x, y, width, len(rows) * ROW_HEIGHT) + draw_list_group_shell(container_rect, style=PANEL_STYLE) for index, row in enumerate(rows): - row_rect = rl.Rectangle(x, y + index * self.ROW_HEIGHT, width, self.ROW_HEIGHT) + row_rect = rl.Rectangle(x, y + index * ROW_HEIGHT, width, ROW_HEIGHT) self._draw_row(row_rect, row, is_last=index == len(rows) - 1) def _draw_features_tab(self, y: float, x: float, width: float): @@ -381,12 +381,12 @@ class VehicleSettingsManagerView(Widget): def _draw_row_group(self, y: float, x: float, width: float, rows: list[dict]): if not rows: return y - container_rect = rl.Rectangle(x, y, width, len(rows) * self.ROW_HEIGHT) - draw_list_group_shell(container_rect) + container_rect = rl.Rectangle(x, y, width, len(rows) * ROW_HEIGHT) + draw_list_group_shell(container_rect, style=PANEL_STYLE) for index, row in enumerate(rows): - row_rect = rl.Rectangle(x, y + index * self.ROW_HEIGHT, width, self.ROW_HEIGHT) + row_rect = rl.Rectangle(x, y + index * ROW_HEIGHT, width, ROW_HEIGHT) self._draw_row(row_rect, row, is_last=index == len(rows) - 1) - return y + len(rows) * self.ROW_HEIGHT + self.SECTION_GAP + return y + len(rows) * ROW_HEIGHT def _draw_row(self, rect: rl.Rectangle, row: dict, is_last: bool): target_id = row["target_id"] @@ -398,7 +398,7 @@ class VehicleSettingsManagerView(Widget): rect, title=row["title"], subtitle=row.get("subtitle", ""), toggle_value=row["get_state"](), hovered=hovered, pressed=pressed, is_last=is_last, show_chevron=False, title_size=34, subtitle_size=22, - style=self.PANEL_STYLE, + style=PANEL_STYLE, ) elif row_type == "select": draw_selection_list_row( @@ -407,9 +407,9 @@ class VehicleSettingsManagerView(Widget): is_last=is_last, action_width=188, action_pill=True, action_pill_width=row.get("pill_width", 108), action_pill_height=44, title_size=34, subtitle_size=22, action_text_size=18, - row_separator=self.PANEL_STYLE.divider_color, - action_fill=self.PANEL_STYLE.current_fill, - action_border=self.PANEL_STYLE.current_border, + row_separator=PANEL_STYLE.divider_color, + action_fill=PANEL_STYLE.current_fill, + action_border=PANEL_STYLE.current_border, action_text_color=AetherListColors.HEADER, ) elif row_type == "info": @@ -417,7 +417,7 @@ class VehicleSettingsManagerView(Widget): rect, title=row["title"], value=row["get_value"](), hovered=False, pressed=False, is_last=is_last, show_chevron=False, title_size=34, subtitle_size=22, - style=self.PANEL_STYLE, + style=PANEL_STYLE, ) def _build_driving_rows(self) -> list[dict]: @@ -498,22 +498,12 @@ class VehicleSettingsManagerView(Widget): return rows -class StarPilotVehicleSettingsLayout(StarPilotPanel): +class StarPilotVehicleSettingsLayout(_SettingsPage): def __init__(self): super().__init__() self._make_options, self._models_by_make, self._models_by_value, self._make_by_model = get_fingerprint_catalog() self._manager_view = VehicleSettingsManagerView(self) - def _render(self, rect: rl.Rectangle): - self._manager_view.render(rect) - - def show_event(self): - super().show_event() - self._manager_view.show_event() - - def hide_event(self): - super().hide_event() - self._manager_view.hide_event() def _action_title(self, key: str) -> str: titles = { @@ -534,15 +524,15 @@ class StarPilotVehicleSettingsLayout(StarPilotPanel): if key == "LKASButtonControl" and self._params.get_bool("RemapCancelToDistance"): if self._params.get_int("LKASButtonControl") != 0: self._params.put_int("LKASButtonControl", 0) - return ACTION_NAME_BY_ID[0] + return tr(ACTION_NAME_BY_ID[0]) idx = self._params.get_int(key) - return ACTION_NAME_BY_ID.get(idx, ACTION_NAMES[0]) + return tr(ACTION_NAME_BY_ID.get(idx, ACTION_NAMES[0])) def _get_available_actions(self, key: str | None = None) -> list[str]: if key == "LKASButtonControl" and self._params.get_bool("RemapCancelToDistance"): - return [ACTION_NAME_BY_ID[0]] + return [tr(ACTION_NAME_BY_ID[0])] cs = starpilot_state.car_state - return [o["name"] for o in ACTION_OPTIONS if cs.hasOpenpilotLongitudinal or not o.get("requires_longitudinal", False)] + return [tr(o["name"]) for o in ACTION_OPTIONS if cs.hasOpenpilotLongitudinal or not o.get("requires_longitudinal", False)] def _on_toggle(self, param_key: str): if param_key == "DisableOpenpilotLongitudinal":