diff --git a/selfdrive/ui/layouts/settings/starpilot/system_settings.py b/selfdrive/ui/layouts/settings/starpilot/system_settings.py index 9d36ef1b6..b217c6bf6 100644 --- a/selfdrive/ui/layouts/settings/starpilot/system_settings.py +++ b/selfdrive/ui/layouts/settings/starpilot/system_settings.py @@ -116,6 +116,11 @@ class SystemSettingsManagerView(PanelManagerView): def vertical_scrolling_disabled(self) -> bool: return True + @property + def _hit_rect(self) -> rl.Rectangle: + base = super()._hit_rect + return rl.Rectangle(base.x, base.y - 72, base.width, base.height + 72) + def __init__(self, controller: StarPilotSystemLayout): super().__init__() self._controller = controller @@ -433,18 +438,28 @@ class SystemSettingsManagerView(PanelManagerView): return 0.0 def _draw_static_elements(self, scroll_rect: rl.Rectangle, content_width: float) -> None: - if not self._uses_two_columns(content_width): - return + pass - column_w = self._column_width(content_width) - right_x = scroll_rect.x + column_w + self.COLUMN_GAP + def _draw_header(self, rect: rl.Rectangle): + content_width = self._scroll_rect.width - AETHER_LIST_METRICS.content_right_gutter + bar_rect = rl.Rectangle(rect.x, rect.y - 6.0, content_width, self._TOPBAR_HEIGHT) + draw_list_group_shell(bar_rect, style=self.PANEL_STYLE) + self._drive_mode_control.render(bar_rect) + total_offset = self._TOPBAR_HEIGHT + self._TOPBAR_GAP + self._scroll_rect.y += total_offset + self._scroll_rect.height = max(0.0, self._scroll_rect.height - total_offset) - btn_size = 32.0 - btn_rect = rl.Rectangle( - right_x + column_w - 12 - 44 - btn_size, - scroll_rect.y + self._system_max_container_h - 12 - 10 - btn_size, - btn_size, btn_size, - ) + self._draw_breadcrumb_first_aid() + + def _draw_breadcrumb_first_aid(self): + top_bar_height = 72 + shell_w = min(self._rect.width - AETHER_LIST_METRICS.outer_margin_x * 2, AETHER_LIST_METRICS.max_content_width) + shell_x = self._rect.x + (self._rect.width - shell_w) / 2 + + btn_size = 48.0 + btn_x = shell_x + shell_w - 24 - btn_size + btn_y = self._rect.y - top_bar_height + (top_bar_height - btn_size) / 2 + btn_rect = rl.Rectangle(btn_x, btn_y, btn_size, btn_size) hovered, pressed = self._interactive_state("static:first_aid", btn_rect, pad_y=6) @@ -463,7 +478,6 @@ class SystemSettingsManagerView(PanelManagerView): s = btn_size / 60.0 icon_x = btn_rect.x + (btn_rect.width - 60.0 * s) / 2.0 icon_y = btn_rect.y + (btn_rect.height - 60.0 * s) / 2.0 - if pressed: icon_color = rl.Color(139, 92, 246, 190) elif hovered: @@ -472,15 +486,6 @@ class SystemSettingsManagerView(PanelManagerView): icon_color = rl.Color(160, 170, 185, 80) draw_custom_icon("first_aid", icon_x, icon_y, s, icon_color) - def _draw_header(self, rect: rl.Rectangle): - content_width = self._scroll_rect.width - AETHER_LIST_METRICS.content_right_gutter - bar_rect = rl.Rectangle(rect.x, rect.y - 6.0, content_width, self._TOPBAR_HEIGHT) - draw_list_group_shell(bar_rect, style=self.PANEL_STYLE) - self._drive_mode_control.render(bar_rect) - total_offset = self._TOPBAR_HEIGHT + self._TOPBAR_GAP - self._scroll_rect.y += total_offset - self._scroll_rect.height = max(0.0, self._scroll_rect.height - total_offset) - def _measure_content_height(self, width: float) -> float: hdr_h = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP display_h = self._slider_section_height(self._display_slider_keys, width) + 4 + hdr_h @@ -670,45 +675,37 @@ class AetherBackupsCareDialog(Widget): def _render(self, rect: rl.Rectangle): rl.draw_rectangle(0, 0, gui_app.width, gui_app.height, rl.Color(0, 0, 0, 160)) - dialog_w = 960 - dialog_h = 660 + dialog_w = min(2320, int(rect.width - 40)) + dialog_h = min(1015, int(rect.height - 40)) dx = rect.x + (rect.width - dialog_w) / 2 dy = rect.y + (rect.height - dialog_h) / 2 - MARGIN = 40 - COL_GAP = 24 - content_w = dialog_w - MARGIN * 2 - btn_pad = 12.0 - col_w = (content_w - btn_pad * 2 - COL_GAP) / 2 - d_rect = snap_rect(rl.Rectangle(dx, dy, dialog_w, dialog_h)) - draw_rounded_fill(d_rect, rl.Color(10, 12, 16, 255), radius_px=24) - draw_rounded_stroke(d_rect, rl.Color(255, 255, 255, 16), radius_px=24) - rl.draw_rectangle_rec(rl.Rectangle(d_rect.x, d_rect.y, d_rect.width, 4), self._color) + draw_rounded_fill(d_rect, rl.Color(10, 12, 16, 255), radius_px=35) + draw_rounded_stroke(d_rect, rl.Color(255, 255, 255, 16), radius_px=35) + rl.draw_rectangle_rec(rl.Rectangle(d_rect.x, d_rect.y, d_rect.width, 3), self._color) title_text = tr("Maintenance") - title_size = 32 + title_size = 64 ts = measure_text_cached(self._font_title, title_text, title_size) - rl.draw_text_ex(self._font_title, title_text, rl.Vector2(round(dx + (dialog_w - ts.x) / 2), round(dy + (84 - title_size) / 2)), title_size, 0, rl.WHITE) + rl.draw_text_ex(self._font_title, title_text, rl.Vector2(round(dx + (dialog_w - ts.x) / 2), round(dy + 87)), title_size, 0, rl.WHITE) - status_rect = snap_rect(rl.Rectangle(dx + MARGIN, dy + 84, content_w, 90)) + MARGIN = 80 + content_w = dialog_w - MARGIN * 2 + + status_rect = snap_rect(rl.Rectangle(dx + MARGIN, dy + 170, content_w, 80)) draw_list_group_shell(status_rect, style=PANEL_STYLE) - gui_label(rl.Rectangle(status_rect.x + 16, status_rect.y + 8, status_rect.width - 32, 18), - tr("System Status"), 14, AetherListColors.MUTED, FontWeight.SEMI_BOLD) + gui_label(rl.Rectangle(status_rect.x + 20, status_rect.y + 10, status_rect.width - 40, 24), + tr("System Status"), 22, AetherListColors.MUTED, FontWeight.SEMI_BOLD) - metric_rows = [ - (tr("Storage"), self._controller.storage_summary()), - (tr("System Backups"), self._controller.backup_count_text()), - (tr("Toggle Snapshots"), self._controller.toggle_backup_count_text()), - ] - metric_label_w = 160.0 - for i, (label, value) in enumerate(metric_rows): - row_y = status_rect.y + 32 + i * 16 - gui_label(rl.Rectangle(status_rect.x + 16, row_y, metric_label_w, 16), - label, 14, AetherListColors.MUTED, FontWeight.MEDIUM) - gui_label(rl.Rectangle(status_rect.x + 16 + metric_label_w, row_y, status_rect.width - 32 - metric_label_w, 16), - value, 14, AetherListColors.HEADER, FontWeight.MEDIUM) + storage_text = tr("Storage: {}").format(self._controller.storage_summary()) + backup_text = tr("Backups: {} • Snapshots: {}").format( + self._controller.backup_count_text(), self._controller.toggle_backup_count_text()) + gui_label(rl.Rectangle(status_rect.x + 20, status_rect.y + 40, status_rect.width - 40, 24), + storage_text, 22, AetherListColors.HEADER, FontWeight.MEDIUM) + gui_label(rl.Rectangle(status_rect.x + 300, status_rect.y + 40, status_rect.width - 320, 24), + backup_text, 22, AetherListColors.HEADER, FontWeight.MEDIUM) mouse_pos = gui_app.last_mouse_event.pos @@ -716,10 +713,15 @@ class AetherBackupsCareDialog(Widget): btn_border = rl.Color(255, 255, 255, 40) btn_fill_hover = rl.Color(30, 32, 42, 255) btn_fill_pressed = mix_colors(self._color, rl.Color(0, 0, 0, 255), 0.15) - btn_radius = 14.0 + btn_radius = 18.0 + COL_GAP = 24 + ROW_GAP = 20 + btn_pad = 16.0 + BTN_HEIGHT = 120.0 + col_w = (content_w - btn_pad * 2 - COL_GAP) / 2 - btn_group_y = dy + 192 - btn_group_h = 4 * 68 + 3 * 14 + btn_pad * 2 + btn_group_y = dy + 278 + btn_group_h = btn_pad * 2 + 4 * BTN_HEIGHT + 3 * ROW_GAP btn_group_rect = snap_rect(rl.Rectangle(dx + MARGIN, btn_group_y, content_w, btn_group_h)) draw_list_group_shell(btn_group_rect, style=PANEL_STYLE) @@ -729,8 +731,8 @@ class AetherBackupsCareDialog(Widget): row = i % 4 col = i // 4 bx = btn_group_rect.x + btn_pad + col * (col_w + COL_GAP) - by = btn_group_rect.y + btn_pad + row * (68 + 14) - btn_rect = snap_rect(rl.Rectangle(bx, by, col_w, 68)) + by = btn_group_rect.y + btn_pad + row * (BTN_HEIGHT + ROW_GAP) + btn_rect = snap_rect(rl.Rectangle(bx, by, col_w, BTN_HEIGHT)) self._button_rects[btn_id] = btn_rect hovered = rl.check_collision_point_rec(mouse_pos, btn_rect) @@ -762,20 +764,22 @@ class AetherBackupsCareDialog(Widget): draw_rounded_fill(btn_rect, fill, radius_px=btn_radius) draw_rounded_stroke(btn_rect, border, thickness=2, radius_px=btn_radius) - font_size = 20 + font_size = 36 draw_text_fit_common( self._font_btn, btn["text"], - rl.Vector2(btn_rect.x + 12, btn_rect.y + (btn_rect.height - font_size) / 2), - btn_rect.width - 24, + rl.Vector2(btn_rect.x + 16, btn_rect.y + (btn_rect.height - font_size) / 2), + btn_rect.width - 32, font_size, align_center=True, color=text_color, ) - cx = dx + (dialog_w - 320) / 2 - cy = d_rect.y + d_rect.height - 36 - 72 - self._close_rect = snap_rect(rl.Rectangle(cx, cy, 320, 72)) + close_w = 600.0 + close_h = 110.0 + cx = dx + (dialog_w - close_w) / 2 + cy = btn_group_rect.y + btn_group_rect.height + 40 + self._close_rect = snap_rect(rl.Rectangle(cx, cy, close_w, close_h)) close_hovered = rl.check_collision_point_rec(mouse_pos, self._close_rect) close_pressed = self._pressed_btn_id == "close" @@ -790,10 +794,11 @@ class AetherBackupsCareDialog(Widget): close_fill = rl.Color(255, 255, 255, 14) close_border = rl.Color(255, 255, 255, 28) - draw_soft_card(self._close_rect, close_fill, close_border) + draw_rounded_fill(self._close_rect, close_fill, radius_px=28) + draw_rounded_stroke(self._close_rect, close_border, thickness=2, radius_px=28) close_text = tr("Close") - close_size = 22 + close_size = 38 cts = measure_text_cached(self._font_btn, close_text, close_size) rl.draw_text_ex( self._font_btn,