BigUI WIP: Cleanerish

This commit is contained in:
firestarsdog
2026-05-01 01:35:44 -04:00
parent eedcfe3c56
commit ae4c155c6e
5 changed files with 119 additions and 115 deletions
@@ -333,6 +333,58 @@ def draw_list_panel_shell(frame: AetherListFrame, style: PanelStyle | None = Non
_draw_rounded_stroke(glow_rect, _with_alpha(glow, 14), radius_px=20)
def init_list_panel(rect: rl.Rectangle, style: PanelStyle | None = None) -> tuple[AetherListFrame, rl.Rectangle, float]:
frame = build_list_panel_frame(rect)
draw_list_panel_shell(frame, style)
scroll_rect = frame.scroll
content_width = scroll_rect.width - AETHER_LIST_METRICS.content_right_gutter
return frame, scroll_rect, content_width
def draw_interactive_rect(target_id: str, rect: rl.Rectangle, interactive_rects: dict[str, rl.Rectangle],
pressed_target: str | None, scroll_rect: rl.Rectangle | None = None,
pad_x: float = 6, pad_y: float = 0) -> tuple[bool, bool]:
interactive_rects[target_id] = rect
mouse_pos = gui_app.last_mouse_event.pos
hovered = _point_hits(mouse_pos, rect, scroll_rect, pad_x=pad_x, pad_y=pad_y)
pressed = pressed_target == target_id and hovered
return hovered, pressed
def resolve_interactive_target(mouse_pos: MousePos, interactive_rects: dict[str, rl.Rectangle],
scroll_rect: rl.Rectangle | None = None,
pad_x: float = 6, pad_y: float = 0) -> str | None:
for target_id, rect in interactive_rects.items():
if _point_hits(mouse_pos, rect, scroll_rect, pad_x=pad_x, pad_y=pad_y):
return target_id
return None
PANEL_HEADER_TITLE_Y: int = 4
PANEL_HEADER_SUBTITLE_Y: int = 48
PANEL_HEADER_TITLE_FONT_SIZE: int = 40
PANEL_HEADER_SUBTITLE_FONT_SIZE: int = 22
PANEL_HEADER_TITLE_FONT: FontWeight = FontWeight.SEMI_BOLD
PANEL_HEADER_SUBTITLE_FONT: FontWeight = FontWeight.NORMAL
def draw_settings_panel_header(header_rect: rl.Rectangle, title: str, subtitle: str | None = None,
*,
title_size: int = PANEL_HEADER_TITLE_FONT_SIZE,
subtitle_size: int = PANEL_HEADER_SUBTITLE_FONT_SIZE,
max_title_width: float = 0.55,
max_subtitle_width: float = 0.58,
title_color: rl.Color = AetherListColors.HEADER,
subtitle_color: rl.Color = AetherListColors.SUBTEXT,
title_weight: FontWeight = PANEL_HEADER_TITLE_FONT,
subtitle_weight: FontWeight = PANEL_HEADER_SUBTITLE_FONT):
title_rect = rl.Rectangle(header_rect.x, header_rect.y + PANEL_HEADER_TITLE_Y, header_rect.width * max_title_width, title_size + 2)
gui_label(title_rect, title, title_size, title_color, title_weight)
if subtitle:
subtitle_rect = rl.Rectangle(header_rect.x, header_rect.y + PANEL_HEADER_SUBTITLE_Y, header_rect.width * max_subtitle_width, subtitle_size + 4)
gui_label(subtitle_rect, subtitle, subtitle_size, subtitle_color, subtitle_weight)
def draw_soft_card(rect: rl.Rectangle, fill: rl.Color, border: rl.Color, radius: float = 0.08, segments: int = 18):
radius_px = radius * min(rect.width, rect.height)
_draw_rounded_fill(rect, fill, radius_px=radius_px, segments=segments)
@@ -38,6 +38,7 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
AetherListColors,
AetherScrollbar,
AetherSliderDialog,
DEFAULT_PANEL_STYLE,
_point_hits,
draw_action_rail,
draw_action_pill,
@@ -52,29 +53,15 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
draw_list_scroll_fades,
draw_section_header,
draw_settings_list_row,
draw_settings_panel_header,
draw_status_led,
draw_overflow_dots,
init_list_panel,
draw_interactive_rect,
resolve_interactive_target,
)
MODEL_PANEL_BG = AetherListColors.PANEL_BG
MODEL_HEADER_TEXT = AetherListColors.HEADER
MODEL_SUBTEXT = AetherListColors.SUBTEXT
MODEL_MUTED = AetherListColors.MUTED
MODEL_ROW_BG = AetherListColors.ROW_BG
MODEL_ROW_BORDER = AetherListColors.ROW_BORDER
MODEL_ROW_SEPARATOR = AetherListColors.ROW_SEPARATOR
MODEL_ROW_HOVER = AetherListColors.ROW_HOVER
MODEL_CURRENT_BG = AetherListColors.CURRENT_BG
MODEL_CURRENT_BORDER = AetherListColors.CURRENT_BORDER
MODEL_ACTION_BG = AetherListColors.ACTION_BG
MODEL_ACTION_SEPARATOR = AetherListColors.ACTION_SEPARATOR
MODEL_PRIMARY = AetherListColors.PRIMARY
MODEL_PRIMARY_SOFT = AetherListColors.PRIMARY_SOFT
MODEL_DANGER = AetherListColors.DANGER
MODEL_DANGER_SOFT = AetherListColors.DANGER_SOFT
MODEL_WARNING = AetherListColors.WARNING
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
@@ -86,6 +73,7 @@ BUTTON_HEIGHT = AETHER_LIST_METRICS.header_button_height
FADE_HEIGHT = AETHER_LIST_METRICS.fade_height
CONFIRM_TIMEOUT_SECONDS = 3.0
TRANSITION_SECONDS = 0.24
PANEL_STYLE = DEFAULT_PANEL_STYLE
@dataclass
@@ -309,17 +297,11 @@ class DrivingModelManagerView(Widget):
self._utility_rects.clear()
self._menu_sub_rects.clear()
frame = build_list_panel_frame(rect)
frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE)
self._shell_rect = frame.shell
draw_list_panel_shell(frame)
header_rect = frame.header
self._draw_header(header_rect)
scroll_rect = frame.scroll
self._scroll_rect = scroll_rect
content_width = scroll_rect.width - AETHER_LIST_METRICS.content_right_gutter
self._draw_header(frame.header)
self._content_height = self._measure_content_height(content_width)
self._scroll_panel.set_enabled(lambda: not self._controller._is_download_active())
self._scroll_offset = self._scroll_panel.update(scroll_rect, max(self._content_height, scroll_rect.height))
@@ -331,22 +313,16 @@ class DrivingModelManagerView(Widget):
if self._content_height > scroll_rect.height:
self._draw_scrollbar(scroll_rect)
draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, MODEL_PANEL_BG, fade_height=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):
title_rect = rl.Rectangle(rect.x, rect.y + 4, rect.width * 0.55, 40)
gui_label(title_rect, tr("Driving Models"), 40, MODEL_HEADER_TEXT, FontWeight.SEMI_BOLD)
subtitle_text = self._controller.header_description_text()
if subtitle_text:
subtitle_rect = rl.Rectangle(rect.x, rect.y + 48, rect.width * 0.58, 36)
gui_label(subtitle_rect, subtitle_text, 24, MODEL_SUBTEXT, FontWeight.NORMAL)
draw_settings_panel_header(rect, tr("Driving Models"), self._controller.header_description_text(), subtitle_size=24)
current_label_rect = rl.Rectangle(rect.x, rect.y + 96, 150, 22)
gui_label(current_label_rect, tr("Current Model"), 20, MODEL_MUTED, FontWeight.MEDIUM)
gui_label(current_label_rect, tr("Current Model"), 20, AetherListColors.MUTED, FontWeight.MEDIUM)
current_value_rect = rl.Rectangle(rect.x + 150, rect.y + 94, rect.width * 0.44, 24)
gui_label(current_value_rect, self._controller._current_model_name, 22, MODEL_HEADER_TEXT, FontWeight.MEDIUM)
gui_label(current_value_rect, self._controller._current_model_name, 22, AetherListColors.HEADER, FontWeight.MEDIUM)
right_panel_w = min(390, rect.width * 0.35)
btn_gap = 10
@@ -422,12 +398,11 @@ class DrivingModelManagerView(Widget):
body_inset_x=48,
title_top_padding=42,
body_height=72,
fill=rl.Color(255, 255, 255, 5),
border=rl.Color(255, 255, 255, 14),
style=PANEL_STYLE,
)
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)
draw_section_header(rl.Rectangle(x, y, width - AETHER_LIST_METRICS.content_right_gutter, SECTION_HEADER_HEIGHT), title, style=PANEL_STYLE)
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
for index, entry in enumerate(entries):
@@ -457,17 +432,17 @@ class DrivingModelManagerView(Widget):
pressed=pressed,
is_last=is_last,
alpha=alpha,
row_bg=MODEL_ROW_BG,
row_border=MODEL_ROW_BORDER,
row_separator=MODEL_ROW_SEPARATOR,
row_hover=MODEL_ROW_HOVER,
current_bg=MODEL_CURRENT_BG,
current_border=MODEL_CURRENT_BORDER,
row_bg=AetherListColors.ROW_BG,
row_border=AetherListColors.ROW_BORDER,
row_separator=AetherListColors.ROW_SEPARATOR,
row_hover=AetherListColors.ROW_HOVER,
current_bg=AetherListColors.CURRENT_BG,
current_border=AetherListColors.CURRENT_BORDER,
row_radius=ROW_RADIUS,
separator_inset=22,
)
action_rect = draw_action_rail(draw_rect, ACTION_WIDTH, current=current, alpha=alpha, fill=MODEL_ACTION_BG, separator=MODEL_ACTION_SEPARATOR, inset_y=18)
action_rect = draw_action_rail(draw_rect, ACTION_WIDTH, current=current, alpha=alpha, fill=AetherListColors.ACTION_BG, separator=AetherListColors.ACTION_SEPARATOR, inset_y=18)
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")
@@ -499,11 +474,11 @@ class DrivingModelManagerView(Widget):
draw_heart_icon(heart_center, heart_color)
heart_offset = 34
title_rect = rl.Rectangle(rect.x + heart_offset, rect.y, rect.width - heart_offset, 34)
gui_label(title_rect, entry.name, 34, MODEL_HEADER_TEXT, FontWeight.MEDIUM)
gui_label(title_rect, entry.name, 34, AetherListColors.HEADER, FontWeight.MEDIUM)
meta_parts = [part for part in (entry.series, entry.released) if part]
meta_rect = rl.Rectangle(rect.x, rect.y + 42, rect.width, 24)
gui_label(meta_rect, "".join(meta_parts), 22, MODEL_SUBTEXT, FontWeight.NORMAL)
gui_label(meta_rect, "".join(meta_parts), 22, AetherListColors.SUBTEXT, FontWeight.NORMAL)
badge_parts: list[str] = []
if current:
@@ -519,18 +494,18 @@ class DrivingModelManagerView(Widget):
if badge_parts:
badge_rect = rl.Rectangle(rect.x, rect.y + 78, rect.width, 22)
badge_color = MODEL_WARNING if entry.partial else MODEL_MUTED
badge_color = AetherListColors.WARNING if entry.partial else AetherListColors.MUTED
gui_label(badge_rect, "".join(badge_parts), 20, badge_color, FontWeight.MEDIUM)
def _draw_download_action(self, rect: rl.Rectangle):
center_x = rect.x + rect.width / 2
center_y = rect.y + rect.height / 2 - 8
draw_download_icon(rl.Vector2(center_x, center_y), MODEL_HEADER_TEXT)
draw_download_icon(rl.Vector2(center_x, center_y), AetherListColors.HEADER)
gui_label(
rl.Rectangle(rect.x + 16, rect.y + rect.height - 40, rect.width - 32, 22),
tr("Download"),
18,
MODEL_SUBTEXT,
AetherListColors.SUBTEXT,
FontWeight.MEDIUM,
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
)
@@ -538,14 +513,14 @@ class DrivingModelManagerView(Widget):
def _draw_downloading_action(self, rect: rl.Rectangle, progress_text: str):
center = rl.Vector2(rect.x + rect.width / 2, rect.y + rect.height / 2 - 8)
phase = (time.monotonic() * 240.0) % 360.0
draw_busy_ring(center, phase, MODEL_PRIMARY)
draw_busy_ring(center, phase, AetherListColors.PRIMARY)
label = progress_text if progress_text else tr("Downloading")
gui_label(
rl.Rectangle(rect.x + 16, rect.y + rect.height - 40, rect.width - 32, 22),
label,
17,
MODEL_SUBTEXT,
AetherListColors.SUBTEXT,
FontWeight.MEDIUM,
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
)
@@ -555,12 +530,12 @@ class DrivingModelManagerView(Widget):
# Three-dot menu indicator
center_x = rect.x + rect.width / 2
center_y = rect.y + rect.height / 2 - 10
draw_overflow_dots(rl.Vector2(center_x, center_y), rl.Color(MODEL_HEADER_TEXT.r, MODEL_HEADER_TEXT.g, MODEL_HEADER_TEXT.b, min(MODEL_HEADER_TEXT.a, 200)))
draw_overflow_dots(rl.Vector2(center_x, center_y), rl.Color(AetherListColors.HEADER.r, AetherListColors.HEADER.g, AetherListColors.HEADER.b, min(AetherListColors.HEADER.a, 200)))
gui_label(
rl.Rectangle(rect.x + 16, rect.y + rect.height - 38, rect.width - 32, 22),
tr("Options"),
18,
MODEL_SUBTEXT,
AetherListColors.SUBTEXT,
FontWeight.MEDIUM,
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
)
@@ -578,31 +553,31 @@ class DrivingModelManagerView(Widget):
self._menu_sub_rects[f"{entry.key}:favorite"] = fav_rect
# Delete button
draw_action_pill(delete_rect, tr("Delete"), MODEL_DANGER_SOFT, rl.Color(MODEL_DANGER.r, MODEL_DANGER.g, MODEL_DANGER.b, min(MODEL_DANGER.a, 70)), MODEL_DANGER)
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)
# Favorite toggle button
is_fav = entry.user_favorite
fav_fill = rl.Color(210, 100, 130, 44) if is_fav else MODEL_PRIMARY_SOFT
fav_border = rl.Color((210 if is_fav else MODEL_PRIMARY.r), (100 if is_fav else MODEL_PRIMARY.g), (130 if is_fav else MODEL_PRIMARY.b), min((255 if is_fav else MODEL_PRIMARY.a), 70))
fav_text_color = rl.Color(210, 100, 130, 255) if is_fav else MODEL_PRIMARY
fav_fill = rl.Color(210, 100, 130, 44) if is_fav else AetherListColors.PRIMARY_SOFT
fav_border = rl.Color((210 if is_fav else AetherListColors.PRIMARY.r), (100 if is_fav else AetherListColors.PRIMARY.g), (130 if is_fav else AetherListColors.PRIMARY.b), min((255 if is_fav else AetherListColors.PRIMARY.a), 70))
fav_text_color = rl.Color(210, 100, 130, 255) if is_fav else AetherListColors.PRIMARY
fav_label = tr("Unfavorite") if is_fav else tr("Favorite")
draw_action_pill(fav_rect, fav_label, fav_fill, fav_border, fav_text_color)
def _draw_current_action(self, rect: rl.Rectangle):
chip_rect = rl.Rectangle(rect.x + 24, rect.y + (rect.height - 42) / 2, rect.width - 48, 42)
AetherChip(tr("Current"), rl.Color(89, 116, 151, 26), rl.Color(116, 136, 168, 52), MODEL_HEADER_TEXT, font_size=18).render(chip_rect)
AetherChip(tr("Current"), rl.Color(89, 116, 151, 26), rl.Color(116, 136, 168, 52), AetherListColors.HEADER, font_size=18).render(chip_rect)
def _draw_protected_action(self, rect: rl.Rectangle):
chip_rect = rl.Rectangle(rect.x + 20, rect.y + (rect.height - 42) / 2, rect.width - 40, 42)
AetherChip(tr("Protected"), rl.Color(255, 255, 255, 10), MODEL_MUTED, MODEL_SUBTEXT, font_size=18).render(chip_rect)
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
draw_section_header(rl.Rectangle(x, y, content_w, SECTION_HEADER_HEIGHT), tr("Automation and Tuning"))
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
container_rect = rl.Rectangle(x, y, content_w, len(rows) * UTILITY_ROW_HEIGHT)
draw_list_group_shell(container_rect, fill=rl.Color(255, 255, 255, 4), border=rl.Color(255, 255, 255, 15))
draw_list_group_shell(container_rect, style=PANEL_STYLE)
for index, row in enumerate(rows):
row_rect = rl.Rectangle(x, y + index * UTILITY_ROW_HEIGHT, content_w, UTILITY_ROW_HEIGHT)
@@ -622,6 +597,7 @@ class DrivingModelManagerView(Widget):
hovered=hovered,
pressed=pressed,
is_last=is_last,
style=PANEL_STYLE,
)
def _draw_scrollbar(self, rect: rl.Rectangle):
@@ -36,7 +36,9 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
draw_tab_card,
draw_selection_list_row,
draw_list_scroll_fades,
draw_settings_panel_header,
draw_soft_card,
init_list_panel,
_point_hits,
)
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanel
@@ -206,7 +208,7 @@ class MapStatusCard(Widget):
selection_chip_rect,
self._controller._selected_summary_text(),
rl.Color(94, 168, 130, 22),
rl.Color(94, 168, 130, 44),
AetherListColors.SUCCESS_SOFT,
AetherListColors.HEADER,
font_size=15,
)
@@ -1121,21 +1123,16 @@ class StarPilotMapsLayout(StarPilotPanel):
def _render(self, rect: rl.Rectangle):
self.set_rect(rect)
frame = build_list_panel_frame(rect)
draw_list_panel_shell(frame, MAPS_PANEL_STYLE)
frame, scroll_rect, content_width = init_list_panel(rect, MAPS_PANEL_STYLE)
hdr = frame.header
title_y = hdr.y + HEADER_TOP_OFFSET
subtitle_y = hdr.y + 48
gui_label(rl.Rectangle(hdr.x, title_y, hdr.width, HEADER_TITLE_HEIGHT), tr("Map Data"), 40, AetherListColors.HEADER, FontWeight.SEMI_BOLD)
gui_label(rl.Rectangle(hdr.x, subtitle_y, hdr.width * 0.60, HEADER_SUBTITLE_HEIGHT), tr("Use offline maps for speed-limit control and keep only the regions you need."), 22, AetherListColors.SUBTEXT, FontWeight.NORMAL)
draw_settings_panel_header(hdr, tr("Map Data"), tr("Use offline maps for speed-limit control and keep only the regions you need."),
max_title_width=1.0, max_subtitle_width=0.60)
header_status_y = subtitle_y + HEADER_SUBTITLE_HEIGHT + 12
header_status_y = hdr.y + 48 + HEADER_SUBTITLE_HEIGHT + 12
header_status_rect = rl.Rectangle(hdr.x, header_status_y, hdr.width, hdr.y + hdr.height - header_status_y - HEADER_BOTTOM_GAP)
self._status_card.render(header_status_rect)
scroll_rect = frame.scroll
content_width = scroll_rect.width - AETHER_LIST_METRICS.content_right_gutter
scroll_content_rect = rl.Rectangle(scroll_rect.x, scroll_rect.y, scroll_rect.width, scroll_rect.height)
self._content_height = self._measure_content_height(content_width)
self._scroll_panel.set_enabled(self.is_visible)
@@ -1,7 +1,5 @@
from __future__ import annotations
import math
import subprocess
import time
from pathlib import Path
import pyray as rl
@@ -10,26 +8,22 @@ from openpilot.common.basedir import BASEDIR
from openpilot.starpilot.common.starpilot_variables import ACTIVE_THEME_PATH
from openpilot.system.ui.lib.application import gui_app, FontWeight, MouseEvent, MousePos
from openpilot.system.ui.lib.multilang import tr, tr_noop
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_label
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.lib.starpilot_state import starpilot_state
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanel
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
AETHER_LIST_METRICS,
AetherListColors,
build_list_panel_frame,
draw_list_panel_shell,
AetherContinuousSlider,
AetherListColors,
DEFAULT_PANEL_STYLE,
_point_hits,
draw_settings_panel_header,
draw_toggle_pill,
init_list_panel,
)
MODEL_PANEL_BG = AetherListColors.PANEL_BG
MODEL_HEADER_TEXT = AetherListColors.HEADER
MODEL_SUBTEXT = AetherListColors.SUBTEXT
MODEL_MUTED = AetherListColors.MUTED
PANEL_STYLE = DEFAULT_PANEL_STYLE
SECTION_GAP = AETHER_LIST_METRICS.section_gap
@@ -43,7 +37,6 @@ class SoundsManagerView(Widget):
self._sliders: dict[str, AetherContinuousSlider] = {}
self._slider_was_dragging: dict[str, bool] = {}
self._toggle_rects: dict[str, rl.Rectangle] = {}
self._font = gui_app.font(FontWeight.BOLD)
self._init_sliders()
@@ -109,7 +102,7 @@ class SoundsManagerView(Widget):
def _target_at(self, mouse_pos: MousePos) -> str | None:
for key, rect in self._toggle_rects.items():
if rl.check_collision_point_rec(mouse_pos, rect):
if _point_hits(mouse_pos, rect, pad_x=6, pad_y=6):
return f"toggle:{key}"
return None
@@ -125,16 +118,13 @@ class SoundsManagerView(Widget):
self.set_rect(rect)
self._toggle_rects.clear()
frame = build_list_panel_frame(rect)
draw_list_panel_shell(frame)
frame, _scroll_rect, _content_width = init_list_panel(rect, PANEL_STYLE)
header_rect = frame.header
self._draw_header(header_rect)
self._draw_header(frame.header)
# Reclaim the dead space! The global header allocates 210px, but our text only uses ~100px.
metrics = AETHER_LIST_METRICS
actual_header_height = 100
content_y = header_rect.y + actual_header_height
content_y = frame.header.y + actual_header_height
content_h = (frame.shell.y + frame.shell.height) - content_y - metrics.panel_padding_bottom
content_rect = rl.Rectangle(
@@ -159,11 +149,7 @@ class SoundsManagerView(Widget):
self._slider_was_dragging[key] = is_dragging
def _draw_header(self, rect: rl.Rectangle):
title_rect = rl.Rectangle(rect.x, rect.y + 4, rect.width * 0.55, 40)
gui_label(title_rect, tr("Sounds & Alerts"), 40, MODEL_HEADER_TEXT, FontWeight.SEMI_BOLD)
subtitle_rect = rl.Rectangle(rect.x, rect.y + 48, rect.width * 0.58, 36)
gui_label(subtitle_rect, tr("Manage system volumes and custom alert toggles."), 24, MODEL_SUBTEXT, FontWeight.NORMAL)
draw_settings_panel_header(rect, tr("Sounds & Alerts"), tr("Manage system volumes and custom alert toggles."), subtitle_size=24)
def _draw_volume_section(self, rect: rl.Rectangle):
num_volumes = len(self._controller.VOLUME_KEYS)
@@ -205,7 +191,7 @@ class SoundsManagerView(Widget):
is_enabled = info.get("is_enabled", lambda: True)()
mouse_pos = gui_app.last_mouse_event.pos
hovered = rl.check_collision_point_rec(mouse_pos, padded_rect)
hovered = _point_hits(mouse_pos, padded_rect, pad_x=6, pad_y=6)
pressed = self._pressed_target == f"toggle:{key}"
status_str = tr("ON") if current_val else tr("OFF")
@@ -33,12 +33,14 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
_point_hits,
build_list_panel_frame,
draw_list_panel_shell,
init_list_panel,
draw_list_group_shell,
draw_list_scroll_fades,
draw_metric_strip,
draw_section_header,
draw_selection_list_row,
draw_settings_list_row,
draw_settings_panel_header,
draw_soft_card,
draw_tab_card,
)
@@ -78,9 +80,7 @@ REPORT_CATEGORIES = [
class SystemSettingsManagerView(Widget):
HEADER_TITLE_HEIGHT = 40
HEADER_SUBTITLE_HEIGHT = 24
HEADER_TOP_OFFSET = 4
HEADER_SUMMARY_GAP = 12
HEADER_CARD_HEIGHT = 108
TAB_HEIGHT = 52
@@ -89,9 +89,7 @@ class SystemSettingsManagerView(Widget):
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
SLIDER_ROW_HEIGHT = AETHER_LIST_METRICS.range_row_height
ROW_HEIGHT = AETHER_COMPACT_ROW_HEIGHT
CONTENT_GUTTER = AETHER_LIST_METRICS.content_right_gutter
FADE_HEIGHT = AETHER_LIST_METRICS.fade_height
COLUMN_GAP = 22
TWO_COLUMN_BREAKPOINT = 1180
@@ -495,16 +493,12 @@ class SystemSettingsManagerView(Widget):
def _render(self, rect: rl.Rectangle):
self.set_rect(rect)
frame = build_list_panel_frame(rect)
draw_list_panel_shell(frame, self.PANEL_STYLE)
frame, scroll_rect, content_width = init_list_panel(rect, self.PANEL_STYLE)
self._scroll_rect = scroll_rect
self._drive_mode_control.set_parent_rect(frame.header)
self._draw_header(frame.header)
scroll_rect = frame.scroll
self._scroll_rect = scroll_rect
content_width = scroll_rect.width - self.CONTENT_GUTTER
self._content_height = self._measure_content_height(content_width)
self._scroll_panel.set_enabled(self.is_visible)
self._scroll_offset = self._scroll_panel.update(scroll_rect, max(self._content_height, scroll_rect.height))
@@ -519,12 +513,11 @@ class SystemSettingsManagerView(Widget):
draw_list_scroll_fades(scroll_rect, self._content_height, self._scroll_offset, AetherListColors.PANEL_BG, fade_height=self.FADE_HEIGHT)
def _draw_header(self, rect: rl.Rectangle):
title_y = rect.y + self.HEADER_TOP_OFFSET
subtitle_y = rect.y + 48
gui_label(rl.Rectangle(rect.x, title_y, rect.width * 0.60, self.HEADER_TITLE_HEIGHT), tr("System Settings"), 40, AetherListColors.HEADER, FontWeight.SEMI_BOLD)
gui_label(rl.Rectangle(rect.x, subtitle_y, rect.width * 0.62, self.HEADER_SUBTITLE_HEIGHT), tr("Manage display, backups, connectivity, and device maintenance from one touch-first panel."), 22, AetherListColors.SUBTEXT, FontWeight.NORMAL)
draw_settings_panel_header(rect, tr("System Settings"),
tr("Manage display, backups, connectivity, and device maintenance from one touch-first panel."),
max_title_width=0.60, max_subtitle_width=0.62)
summary_y = subtitle_y + self.HEADER_SUBTITLE_HEIGHT + self.HEADER_SUMMARY_GAP
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)
@@ -753,7 +746,7 @@ class SystemSettingsManagerView(Widget):
subtitle_size=17,
action_text_size=15,
row_separator=self.PANEL_STYLE.divider_color,
action_fill=rl.Color(89, 116, 151, 18),
action_fill=AetherListColors.CURRENT_BG,
action_border=rl.Color(89, 116, 151, 42),
action_text_color=AetherListColors.HEADER,
)