mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-08 15:12:10 +08:00
BigUI WIP: Pass B
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -204,6 +204,11 @@ class StarPilotAppearanceLayout(_SettingsPage):
|
||||
)
|
||||
)
|
||||
|
||||
def _set_developer_sidebar(self, enabled):
|
||||
self._params.put_bool("DeveloperSidebar", enabled)
|
||||
if enabled:
|
||||
self._params.put_bool("DeveloperUI", True)
|
||||
|
||||
def _build_view(self):
|
||||
po = lambda: self._params.get_bool("PedalsOnUI")
|
||||
ol = lambda: starpilot_state.car_state.hasOpenpilotLongitudinal
|
||||
@@ -458,8 +463,8 @@ class StarPilotAppearanceLayout(_SettingsPage):
|
||||
self._dev_rows = [
|
||||
SettingRow("DeveloperSidebar", "toggle", tr_noop("Developer Sidebar"),
|
||||
subtitle=tr_noop("Driving metrics panel on the right"),
|
||||
get_state=lambda: self._params.get_bool("DeveloperSidebar"),
|
||||
set_state=lambda s: self._params.put_bool("DeveloperSidebar", s)),
|
||||
get_state=lambda: bool(self._params.get("DeveloperSidebar") or False),
|
||||
set_state=lambda s: self._set_developer_sidebar(s)),
|
||||
SettingRow("LeadDetectionThreshold", "value", tr_noop("Lead Detection Threshold"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_int('LeadDetectionThreshold', return_default=True, default=35)}%",
|
||||
|
||||
@@ -136,7 +136,7 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
lambda: self._controller.random_model_button_label(),
|
||||
self._controller.toggle_model_randomizer,
|
||||
emphasized=False,
|
||||
font_size=22,
|
||||
font_size=28,
|
||||
)
|
||||
)
|
||||
self._primary_header_button.set_touch_valid_callback(lambda: self._scroll_panel.is_touch_valid())
|
||||
@@ -299,14 +299,14 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
self._random_model_button.render(random_rect)
|
||||
|
||||
# LED indicator
|
||||
led_x = int(random_rect.x + random_rect.width - 26)
|
||||
led_x = int(random_rect.x + random_rect.width - 38)
|
||||
led_y = int(random_rect.y + random_rect.height / 2)
|
||||
randomizer_on = self._controller._params.get_bool("ModelRandomizer")
|
||||
draw_status_led(rl.Vector2(led_x, led_y), randomizer_on)
|
||||
|
||||
def _measure_content_height(self, width: float) -> float:
|
||||
sections = self._build_sections(width)
|
||||
RELOCATED_HEADER_HEIGHT = 74.0
|
||||
RELOCATED_HEADER_HEIGHT = 107.0
|
||||
if not sections:
|
||||
return 260 + RELOCATED_HEADER_HEIGHT
|
||||
return max(sum(height for _key, height in sections) - SECTION_GAP, 0.0) + RELOCATED_HEADER_HEIGHT
|
||||
@@ -337,7 +337,7 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
utility_rows = self._controller.utility_rows()
|
||||
|
||||
y = rect.y + self._scroll_offset
|
||||
RELOCATED_HEADER_HEIGHT = 74.0
|
||||
RELOCATED_HEADER_HEIGHT = 107.0
|
||||
self._draw_relocated_header(rect.x, y, width)
|
||||
y += RELOCATED_HEADER_HEIGHT
|
||||
|
||||
@@ -359,8 +359,8 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
rl.Rectangle(rect.x, rect.y, rect.width, rect.height),
|
||||
self._controller.empty_state_title(),
|
||||
self._controller.empty_state_body(),
|
||||
title_size=32,
|
||||
body_size=24,
|
||||
title_size=46,
|
||||
body_size=35,
|
||||
body_inset_x=48,
|
||||
title_top_padding=42,
|
||||
body_height=72,
|
||||
@@ -442,15 +442,15 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
heart_offset = 0
|
||||
if entry.user_favorite:
|
||||
heart_color = rl.Color(210, 100, 130, 230)
|
||||
heart_center = rl.Vector2(rect.x + 15, rect.y + 17)
|
||||
heart_center = rl.Vector2(rect.x + 22, rect.y + 25)
|
||||
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, AetherListColors.HEADER, FontWeight.MEDIUM)
|
||||
heart_offset = 49
|
||||
title_rect = rl.Rectangle(rect.x + heart_offset, rect.y, rect.width - heart_offset, 49)
|
||||
gui_label(title_rect, entry.name, 49, 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, AetherListColors.SUBTEXT, FontWeight.NORMAL)
|
||||
meta_rect = rl.Rectangle(rect.x, rect.y + 61, rect.width, 35)
|
||||
gui_label(meta_rect, " • ".join(meta_parts), 32, AetherListColors.SUBTEXT, FontWeight.NORMAL)
|
||||
|
||||
badge_parts: list[str] = []
|
||||
if current:
|
||||
@@ -465,18 +465,18 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
badge_parts.append(tr("Popular"))
|
||||
|
||||
if badge_parts:
|
||||
badge_rect = rl.Rectangle(rect.x, rect.y + 78, rect.width, 22)
|
||||
badge_rect = rl.Rectangle(rect.x, rect.y + 113, rect.width, 32)
|
||||
badge_color = AetherListColors.WARNING if entry.partial else AetherListColors.MUTED
|
||||
gui_label(badge_rect, " • ".join(badge_parts), 20, badge_color, FontWeight.MEDIUM)
|
||||
gui_label(badge_rect, " • ".join(badge_parts), 30, 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), AetherListColors.HEADER)
|
||||
gui_label(
|
||||
rl.Rectangle(rect.x + 16, rect.y + rect.height - 40, rect.width - 32, 22),
|
||||
rl.Rectangle(rect.x + 16, rect.y + rect.height - 58, rect.width - 32, 32),
|
||||
tr("Download"),
|
||||
18,
|
||||
26,
|
||||
AetherListColors.SUBTEXT,
|
||||
FontWeight.MEDIUM,
|
||||
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
|
||||
@@ -489,9 +489,9 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
|
||||
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),
|
||||
rl.Rectangle(rect.x + 16, rect.y + rect.height - 58, rect.width - 32, 32),
|
||||
label,
|
||||
17,
|
||||
24,
|
||||
AetherListColors.SUBTEXT,
|
||||
FontWeight.MEDIUM,
|
||||
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
|
||||
@@ -504,22 +504,22 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
center_y = rect.y + rect.height / 2 - 10
|
||||
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),
|
||||
rl.Rectangle(rect.x + 16, rect.y + rect.height - 55, rect.width - 32, 32),
|
||||
tr("Options"),
|
||||
18,
|
||||
26,
|
||||
AetherListColors.SUBTEXT,
|
||||
FontWeight.MEDIUM,
|
||||
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
|
||||
)
|
||||
else:
|
||||
# Expanded sub-button menu
|
||||
btn_h = 44
|
||||
gap = 8
|
||||
btn_h = 64
|
||||
gap = 12
|
||||
total_h = btn_h * 2 + gap
|
||||
start_y = rect.y + (rect.height - total_h) / 2
|
||||
|
||||
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)
|
||||
delete_rect = rl.Rectangle(rect.x + 14, start_y, rect.width - 20, btn_h)
|
||||
fav_rect = rl.Rectangle(rect.x + 14, start_y + btn_h + gap, rect.width - 20, btn_h)
|
||||
|
||||
self._interactive_rects[f"menu:{entry.key}:delete"] = delete_rect
|
||||
self._interactive_rects[f"menu:{entry.key}:favorite"] = fav_rect
|
||||
@@ -536,12 +536,12 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
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"), PANEL_STYLE.current_fill, PANEL_STYLE.current_border, AetherListColors.HEADER, font_size=18).render(chip_rect)
|
||||
chip_rect = rl.Rectangle(rect.x + 35, rect.y + (rect.height - 61) / 2, rect.width - 70, 61)
|
||||
AetherChip(tr("Current"), PANEL_STYLE.current_fill, PANEL_STYLE.current_border, AetherListColors.HEADER, font_size=26).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), AetherListColors.MUTED, AetherListColors.SUBTEXT, font_size=18).render(chip_rect)
|
||||
chip_rect = rl.Rectangle(rect.x + 29, rect.y + (rect.height - 61) / 2, rect.width - 58, 61)
|
||||
AetherChip(tr("Protected"), rl.Color(255, 255, 255, 10), AetherListColors.MUTED, AetherListColors.SUBTEXT, font_size=26).render(chip_rect)
|
||||
|
||||
def _draw_utility_section(self, x: float, y: float, width: float, rows: list[dict]):
|
||||
content_w = width
|
||||
|
||||
@@ -160,7 +160,7 @@ class LongitudinalManagerView(AetherSettingsView):
|
||||
"on_click": lambda: self._controller._navigate_to("personality")
|
||||
},
|
||||
{
|
||||
"title": tr("Daily QOL & Weather"),
|
||||
"title": tr("Quality of Life"),
|
||||
"desc": tr("Configure cruise intervals, standstill behaviors, gear mapping, and weather presets."),
|
||||
"icon": "sound",
|
||||
"color": "#8B5CF6",
|
||||
@@ -220,8 +220,8 @@ class ConditionalDriveModeView(PanelManagerView):
|
||||
panel_padding_bottom=14,
|
||||
header_height=0,
|
||||
)
|
||||
TAB_HEIGHT = 68
|
||||
TAB_BOTTOM_GAP = 18
|
||||
TAB_HEIGHT = 98
|
||||
TAB_BOTTOM_GAP = 26
|
||||
|
||||
@property
|
||||
def vertical_scrolling_disabled(self) -> bool:
|
||||
@@ -275,7 +275,7 @@ class ConditionalDriveModeView(PanelManagerView):
|
||||
self._update_pagination()
|
||||
|
||||
def _init_toggles(self):
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, force_square=True, min_tile_height=130.0)
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, min_tile_height=130.0)
|
||||
self._child(self._toggle_grid)
|
||||
self.register_page_grid(self._toggle_grid)
|
||||
|
||||
@@ -452,7 +452,7 @@ class ConditionalDriveModeView(PanelManagerView):
|
||||
|
||||
max_container_h = available_h
|
||||
|
||||
left_row_h = max(60.0, (max_container_h - 16.0) / max(1, len(keys)))
|
||||
left_row_h = max(80.0, (max_container_h - 16.0) / max(1, len(keys)))
|
||||
for key in keys:
|
||||
self._adjustor_rows[key].custom_row_height = left_row_h
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ class StarPilotLayout(Widget):
|
||||
self._commit_navigation()
|
||||
|
||||
def _render(self, rect: rl.Rectangle):
|
||||
TOP_BAR_HEIGHT = 110
|
||||
TOP_BAR_HEIGHT = 160
|
||||
content_rect = rl.Rectangle(rect.x, rect.y + TOP_BAR_HEIGHT, rect.width, rect.height - TOP_BAR_HEIGHT)
|
||||
|
||||
# Standardize width to perfectly match subpanel shells
|
||||
@@ -281,20 +281,20 @@ class StarPilotLayout(Widget):
|
||||
shell_x = rect.x + (rect.width - shell_w) / 2
|
||||
|
||||
# 0. Draw top bar with HubTile-style purple glow
|
||||
glass_rect = rl.Rectangle(shell_x, rect.y + 14, shell_w, TOP_BAR_HEIGHT - 24)
|
||||
glass_rect = rl.Rectangle(shell_x, rect.y + 20, shell_w, TOP_BAR_HEIGHT - 35)
|
||||
|
||||
# 0a. Purple glow rings — 4 concentric, fading outward (HubTile parity)
|
||||
for i in range(4, 0, -1):
|
||||
off = i * 2.5
|
||||
gr = rl.Rectangle(glass_rect.x - off, glass_rect.y - off, glass_rect.width + off * 2, glass_rect.height + off * 2)
|
||||
a = int(25 * (1.0 - i / 5))
|
||||
draw_rounded_fill(gr, rl.Color(139, 92, 246, max(0, min(255, a))), radius_px=100)
|
||||
draw_rounded_fill(gr, rl.Color(139, 92, 246, max(0, min(255, a))), radius_px=145)
|
||||
|
||||
# 0b. Dark fill — strict parity with HubTile _HUD_BG_ON
|
||||
draw_rounded_fill(glass_rect, rl.Color(12, 10, 18, 255), radius_px=100)
|
||||
draw_rounded_fill(glass_rect, rl.Color(12, 10, 18, 255), radius_px=145)
|
||||
|
||||
# 0c. Full bright purple border — strict parity
|
||||
draw_rounded_stroke(glass_rect, rl.Color(139, 92, 246, 255), radius_px=100)
|
||||
draw_rounded_stroke(glass_rect, rl.Color(139, 92, 246, 255), radius_px=145)
|
||||
|
||||
# 1. Draw breadcrumbs in top bar
|
||||
crumb_rect = rl.Rectangle(glass_rect.x, glass_rect.y, glass_rect.width, glass_rect.height)
|
||||
|
||||
@@ -214,7 +214,7 @@ class MapStatusCard(Widget):
|
||||
with_alpha(AetherListColors.SUCCESS_SOFT, 22),
|
||||
AetherListColors.SUCCESS_SOFT,
|
||||
AetherListColors.HEADER,
|
||||
font_size=18,
|
||||
font_size=26,
|
||||
)
|
||||
gui_text_box(
|
||||
rl.Rectangle(content_x, title_y + 28, summary_w, 44),
|
||||
@@ -279,7 +279,7 @@ class MapStatusCard(Widget):
|
||||
with_alpha(AetherListColors.DANGER_SOFT, 26 if enabled else 12),
|
||||
with_alpha(AetherListColors.DANGER, 58 if enabled else 24),
|
||||
AetherListColors.HEADER if enabled else AetherListColors.MUTED,
|
||||
font_size=18,
|
||||
font_size=26,
|
||||
)
|
||||
|
||||
if self._controller._download_state.active:
|
||||
@@ -444,13 +444,13 @@ class MapBrowserCard(Widget):
|
||||
hovered=hovered,
|
||||
pressed=self._pressed_target == target_key,
|
||||
is_last=index == len(regions) - 1,
|
||||
action_width=188,
|
||||
action_width=AETHER_LIST_METRICS.action_width,
|
||||
action_pill=True,
|
||||
action_text_size=18,
|
||||
action_pill_height=44,
|
||||
action_pill_width=132 if selected else 108,
|
||||
title_size=34,
|
||||
subtitle_size=22,
|
||||
action_text_size=26,
|
||||
action_pill_height=64,
|
||||
action_pill_width=191 if selected else 156,
|
||||
title_size=49,
|
||||
subtitle_size=32,
|
||||
row_separator=PANEL_STYLE.divider_color,
|
||||
current_bg=PANEL_STYLE.current_fill,
|
||||
current_border=PANEL_STYLE.current_border,
|
||||
@@ -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=34, trailing_size=22, style=PANEL_STYLE)
|
||||
draw_section_header(rect, title, trailing_text=count_text or "", title_size=49, trailing_size=32, style=PANEL_STYLE)
|
||||
|
||||
def _measure_height(self, width: float) -> float:
|
||||
total = 10.0
|
||||
@@ -545,7 +545,6 @@ class StarPilotMapsLayout(StarPilotPanel):
|
||||
self._on_primary_action,
|
||||
enabled=self._primary_action_enabled,
|
||||
emphasized=True,
|
||||
font_size=24,
|
||||
)
|
||||
)
|
||||
self._schedule_button = self._child(
|
||||
@@ -553,7 +552,6 @@ class StarPilotMapsLayout(StarPilotPanel):
|
||||
lambda: tr("Update: {}").format(_localized_schedule_label(self._params.get('PreferredSchedule'))),
|
||||
self._on_schedule,
|
||||
emphasized=False,
|
||||
font_size=21,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ class TileSection:
|
||||
|
||||
|
||||
class SectionedTileLayout(Widget):
|
||||
def __init__(self, section_gap: int = 28, title_height: int = 34, title_gap: int = 12,
|
||||
min_row_height: int = 150, max_row_height: int = 280, top_padding: int = 0,
|
||||
horizontal_padding: int = SPACING.xl, max_content_width: int | None = 1440):
|
||||
def __init__(self, section_gap: int = 28, title_height: int = 49, title_gap: int = 17,
|
||||
min_row_height: int = 218, max_row_height: int = 406, top_padding: int = 0,
|
||||
horizontal_padding: int = SPACING.xl, max_content_width: int | None = 1560):
|
||||
super().__init__()
|
||||
self._sections: list[TileSection] = []
|
||||
self._section_gap = section_gap
|
||||
@@ -34,7 +34,7 @@ class SectionedTileLayout(Widget):
|
||||
self._top_padding = top_padding
|
||||
self._horizontal_padding = horizontal_padding
|
||||
self._max_content_width = max_content_width
|
||||
self._title_font_size = 26
|
||||
self._title_font_size = 38
|
||||
self._font_title = gui_app.font(FontWeight.BOLD)
|
||||
self._is_active = False
|
||||
self._scroll_panel = GuiScrollPanel2(horizontal=False)
|
||||
@@ -109,12 +109,12 @@ class SectionedTileLayout(Widget):
|
||||
total_title_height = sum(self._title_block_height(section, title_height, title_gap) for section in sections)
|
||||
total_section_gaps = section_gap * max(0, len(sections) - 1)
|
||||
fit_row_height = max(0.0, (rect.height - self._top_padding - total_title_height - total_section_gaps - total_internal_gaps) / total_rows)
|
||||
min_row_height = min(self._min_row_height, 124) if rect.width < 960 or compact_pass else self._min_row_height
|
||||
min_row_height = min(self._min_row_height, 180) if rect.width < 960 or compact_pass else self._min_row_height
|
||||
if fit_row_height >= min_row_height:
|
||||
return title_height, title_gap, section_gap, min(fit_row_height, self._max_row_height)
|
||||
title_height = max(24, min(title_height, 28))
|
||||
title_gap = max(4, min(title_gap, 6))
|
||||
section_gap = max(12, min(section_gap, 16))
|
||||
title_height = max(35, min(title_height, 41))
|
||||
title_gap = max(6, min(title_gap, 9))
|
||||
section_gap = max(17, min(section_gap, 23))
|
||||
|
||||
return title_height, title_gap, section_gap, fit_row_height
|
||||
|
||||
|
||||
@@ -117,9 +117,9 @@ class SimpleDownloadManager(Widget):
|
||||
MODE_DOWNLOAD = 2
|
||||
|
||||
MODE_LABELS = ["SELECT", "DELETE", "DOWNLOAD"]
|
||||
ITEM_HEIGHT = 88
|
||||
PILL_HEIGHT = 50
|
||||
PILL_GAP = 10
|
||||
ITEM_HEIGHT = 128
|
||||
PILL_HEIGHT = 73
|
||||
PILL_GAP = 14
|
||||
OUTER_MARGIN = 60
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -24,26 +24,27 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
ToggleTile,
|
||||
DEFAULT_PANEL_STYLE,
|
||||
point_hits,
|
||||
draw_action_pill,
|
||||
draw_list_group_shell,
|
||||
draw_section_header,
|
||||
draw_settings_panel_header,
|
||||
AetherSliderDialog,
|
||||
SECTION_GAP,
|
||||
SECTION_HEADER_HEIGHT,
|
||||
SECTION_HEADER_GAP,
|
||||
GROUP_HEADER_HEIGHT,
|
||||
GROUP_HEADER_GAP,
|
||||
GROUP_HEADER_LINE_GAP,
|
||||
draw_group_header,
|
||||
)
|
||||
|
||||
PANEL_STYLE = DEFAULT_PANEL_STYLE
|
||||
SOUNDS_PANEL_METRICS = replace(
|
||||
COMPACT_PANEL_METRICS,
|
||||
outer_margin_y=14,
|
||||
panel_padding_top=16,
|
||||
outer_margin_y=10,
|
||||
panel_padding_top=12,
|
||||
panel_padding_bottom=14,
|
||||
header_height=0,
|
||||
)
|
||||
|
||||
|
||||
|
||||
class SoundsManagerView(PanelManagerView):
|
||||
METRICS = SOUNDS_PANEL_METRICS
|
||||
|
||||
@@ -71,7 +72,7 @@ class SoundsManagerView(PanelManagerView):
|
||||
)
|
||||
|
||||
def _init_toggles(self):
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, force_square=True, min_tile_height=130.0)
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, min_tile_height=130.0)
|
||||
self._child(self._toggle_grid)
|
||||
self._page_grid = self._toggle_grid
|
||||
|
||||
@@ -235,45 +236,32 @@ class SoundsManagerView(PanelManagerView):
|
||||
def _measure_content_height(self, content_width: float) -> float:
|
||||
col_width = (content_width - SECTION_GAP) / 2
|
||||
|
||||
# Reset any previous custom heights to calculate natural measurements first
|
||||
self._toggle_grid._tile_height = None
|
||||
for key in self._controller.VOLUME_KEYS:
|
||||
self._adjustor_rows[key].custom_row_height = None
|
||||
self._adjustor_rows[self._controller.COOLDOWN_KEY].custom_row_height = None
|
||||
self._toggle_grid._tile_height = None
|
||||
|
||||
default_adjustor_h = float(AETHER_LIST_METRICS.adjustor_row_height)
|
||||
|
||||
# 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 += 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
|
||||
right_natural_container_h = tiles_needed_h
|
||||
|
||||
max_natural_h = max(left_natural_container_h, right_natural_container_h)
|
||||
section_overhead = SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
hdr_h = GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP + GROUP_HEADER_LINE_GAP
|
||||
|
||||
if self._scroll_rect:
|
||||
available_container_h = self._scroll_rect.height - section_overhead - 6.0
|
||||
available_container_h = self._scroll_rect.height - 6.0
|
||||
else:
|
||||
available_container_h = max_natural_h
|
||||
available_container_h = 0.0
|
||||
|
||||
# Always stretch container to fill available height, preventing empty space at bottom
|
||||
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 * 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))
|
||||
left_available_for_rows = available_container_h - 20.0 - 16.0 - hdr_h
|
||||
left_row_h = max(80.0, min(107.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
|
||||
self._adjustor_rows[self._controller.COOLDOWN_KEY].custom_row_height = left_row_h
|
||||
|
||||
self._left_container_h = max_container_h
|
||||
self._tiles_container_h = max_container_h
|
||||
left_content_h = (len(self._controller.VOLUME_KEYS) + 1) * left_row_h + 20 + 16 + hdr_h
|
||||
tiles_needed_h = self.measure_page_grid_height(self._toggle_grid, col_width - 24) + 24 + 8 + hdr_h
|
||||
max_content_h = max(left_content_h, tiles_needed_h)
|
||||
|
||||
return self._compute_two_column_height(section_overhead + max_container_h)
|
||||
self._left_container_h = max_content_h
|
||||
self._tiles_container_h = max_content_h
|
||||
|
||||
return self._compute_two_column_height(max_content_h)
|
||||
|
||||
def _draw_header(self, rect: rl.Rectangle):
|
||||
pass
|
||||
@@ -282,35 +270,6 @@ class SoundsManagerView(PanelManagerView):
|
||||
y = rect.y + self._scroll_offset
|
||||
col_width = (content_width - SECTION_GAP) / 2
|
||||
|
||||
draw_section_header(
|
||||
rl.Rectangle(rect.x, y, col_width, SECTION_HEADER_HEIGHT),
|
||||
tr("Volume"), style=PANEL_STYLE
|
||||
)
|
||||
draw_section_header(
|
||||
rl.Rectangle(rect.x + col_width + SECTION_GAP, y, col_width, SECTION_HEADER_HEIGHT),
|
||||
tr("Alerts"), style=PANEL_STYLE
|
||||
)
|
||||
|
||||
# Draw Reset All button aligned with the Volume header
|
||||
btn_w = 120.0
|
||||
btn_h = 32.0
|
||||
btn_x = rect.x + col_width - btn_w - 8
|
||||
btn_y = y + (SECTION_HEADER_HEIGHT - btn_h) / 2
|
||||
self._reset_rect = rl.Rectangle(btn_x, btn_y, btn_w, btn_h)
|
||||
|
||||
self._interactive_rects["action:restore_defaults"] = self._reset_rect
|
||||
|
||||
hovered = point_hits(gui_app.last_mouse_event.pos, self._reset_rect, self._scroll_rect, pad_x=6, pad_y=0)
|
||||
pressed = self._pressed_target == "action:restore_defaults"
|
||||
draw_action_pill(
|
||||
self._reset_rect, tr("Reset All"),
|
||||
rl.Color(255, 255, 255, 8 if not pressed else 14),
|
||||
rl.Color(255, 255, 255, 18 if not pressed else 28),
|
||||
AetherListColors.SUBTEXT if not hovered else AetherListColors.HEADER,
|
||||
)
|
||||
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
|
||||
self._draw_volume_column(y, rect.x, col_width)
|
||||
self._draw_utility_column(y, rect.x + col_width + SECTION_GAP, col_width)
|
||||
|
||||
@@ -331,6 +290,13 @@ class SoundsManagerView(PanelManagerView):
|
||||
)
|
||||
|
||||
current_y = y + 8
|
||||
current_y = draw_group_header(x + 24, current_y, width - 48, tr("VOLUME"))
|
||||
|
||||
label_rect = rl.Rectangle(x + 24, current_y - GROUP_HEADER_HEIGHT - GROUP_HEADER_LINE_GAP - GROUP_HEADER_GAP, width - 48, GROUP_HEADER_HEIGHT)
|
||||
gui_label(label_rect, tr("Reset All"), 18, AetherListColors.MUTED, FontWeight.NORMAL,
|
||||
alignment=rl.GuiTextAlignment.TEXT_ALIGN_RIGHT)
|
||||
self._reset_rect = rl.Rectangle(label_rect.x + label_rect.width - 80, label_rect.y, 80, 45)
|
||||
self._interactive_rects["action:restore_defaults"] = self._reset_rect
|
||||
for i, (label, keys) in enumerate(groups):
|
||||
if label is not None:
|
||||
divider_h = 4
|
||||
@@ -350,7 +316,10 @@ class SoundsManagerView(PanelManagerView):
|
||||
current_y += row_h
|
||||
|
||||
def _draw_utility_column(self, y: float, x: float, width: float):
|
||||
self._draw_two_column_tile_grid(self._toggle_grid, x, y, width, self._tiles_container_h, title=None, style=PANEL_STYLE)
|
||||
draw_list_group_shell(rl.Rectangle(x, y, width, self._tiles_container_h), style=PANEL_STYLE)
|
||||
header_y = draw_group_header(x + 24, y + 8, width - 48, tr("ALERTS"))
|
||||
avail_h = self._tiles_container_h - (header_y - y)
|
||||
self._render_page_grid(self._toggle_grid, rl.Rectangle(x + 12, header_y, width - 24, max(0.0, avail_h - 12)))
|
||||
|
||||
|
||||
class StarPilotSoundsLayout(_SettingsPage):
|
||||
@@ -375,19 +344,19 @@ class StarPilotSoundsLayout(_SettingsPage):
|
||||
|
||||
COOLDOWN_INFO = {
|
||||
"title": tr_noop("Switchback Mode Cooldown"),
|
||||
"subtitle": tr_noop("Time before switchback re-engages"),
|
||||
"subtitle": "",
|
||||
"min": 0,
|
||||
"max": 30,
|
||||
}
|
||||
VOLUME_INFO = {
|
||||
"WarningImmediateVolume": {"title": tr_noop("Immediate Warning"), "subtitle": tr_noop("Critical safety intervention"), "min": 25},
|
||||
"WarningImmediateVolume": {"title": tr_noop("Immediate Warning"), "subtitle": "", "min": 25},
|
||||
"WarningSoftVolume": {"title": tr_noop("Soft Warning"), "subtitle": "", "min": 25},
|
||||
"RefuseVolume": {"title": tr_noop("Engagement Refused"), "subtitle": "", "min": 0},
|
||||
"PromptDistractedVolume": {"title": tr_noop("Distracted Driver"), "subtitle": "", "min": 0},
|
||||
"EngageVolume": {"title": tr_noop("Engagement Chime"), "subtitle": "", "min": 0},
|
||||
"DisengageVolume": {"title": tr_noop("Disengagement Alert"), "subtitle": "", "min": 0},
|
||||
"PromptVolume": {"title": tr_noop("General Prompt"), "subtitle": tr_noop("System guidance prompt"), "min": 0},
|
||||
"BelowSteerSpeedVolume": {"title": tr_noop("Low Speed Alert"), "subtitle": tr_noop("Minimum speed for steering"), "min": 0},
|
||||
"PromptVolume": {"title": tr_noop("General Prompt"), "subtitle": "", "min": 0},
|
||||
"BelowSteerSpeedVolume": {"title": tr_noop("Low Speed Alert"), "subtitle": "", "min": 0},
|
||||
}
|
||||
|
||||
_sound_player_process = None
|
||||
@@ -399,27 +368,27 @@ class StarPilotSoundsLayout(_SettingsPage):
|
||||
self.ALERT_INFO = {
|
||||
"GreenLightAlert": {
|
||||
"title": tr_noop("Green Light"),
|
||||
"subtitle": tr_noop("When lead car moves at green light"),
|
||||
"subtitle": "",
|
||||
},
|
||||
"LeadDepartingAlert": {
|
||||
"title": tr_noop("Lead Departure"),
|
||||
"subtitle": tr_noop("When lead vehicle pulls away"),
|
||||
"subtitle": "",
|
||||
},
|
||||
"LoudBlindspotAlert": {
|
||||
"title": tr_noop("Loud Blindspot"),
|
||||
"subtitle": tr_noop("Blind spot collision warning"),
|
||||
"subtitle": "",
|
||||
"is_enabled": lambda: starpilot_state.car_state.hasBSM,
|
||||
"disabled_label": tr_noop("Needs BSM")
|
||||
},
|
||||
"LoudBlindspotAlertWhenDisengaged": {
|
||||
"title": tr_noop("Loud While Paused"),
|
||||
"subtitle": tr_noop("When lateral is off or paused"),
|
||||
"subtitle": "",
|
||||
"is_enabled": lambda: starpilot_state.car_state.hasBSM and self._params.get_bool("LoudBlindspotAlert"),
|
||||
"disabled_label": tr_noop("Enable Loud Blindspot")
|
||||
},
|
||||
"SpeedLimitChangedAlert": {
|
||||
"title": tr_noop("Speed Limit"),
|
||||
"subtitle": tr_noop("When posted speed limit changes"),
|
||||
"subtitle": "",
|
||||
"is_enabled": lambda: self._params.get_bool("ShowSpeedLimits") or (
|
||||
starpilot_state.car_state.hasOpenpilotLongitudinal and self._params.get_bool("SpeedLimitController")
|
||||
),
|
||||
|
||||
@@ -35,11 +35,11 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
TileGrid,
|
||||
ToggleTile,
|
||||
draw_list_group_shell,
|
||||
draw_section_header,
|
||||
draw_selection_list_row,
|
||||
draw_settings_panel_header,
|
||||
draw_soft_card,
|
||||
GROUP_HEADER_GAP,
|
||||
GROUP_HEADER_LINE_GAP,
|
||||
GROUP_HEADER_HEIGHT,
|
||||
draw_group_header,
|
||||
draw_tab_bar,
|
||||
@@ -52,8 +52,6 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
draw_text_fit_common,
|
||||
wrap_text,
|
||||
SECTION_GAP,
|
||||
SECTION_HEADER_HEIGHT,
|
||||
SECTION_HEADER_GAP,
|
||||
ROW_HEIGHT,
|
||||
)
|
||||
from openpilot.starpilot.common.connect_server import prepare_konik_server_switch
|
||||
@@ -108,9 +106,9 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
HEADER_SUBTITLE_HEIGHT = 24
|
||||
HEADER_SUMMARY_GAP = 6
|
||||
HEADER_CARD_HEIGHT = 140
|
||||
TAB_HEIGHT = 68
|
||||
TAB_GAP = 10
|
||||
TAB_BOTTOM_GAP = 18
|
||||
TAB_HEIGHT = 98
|
||||
TAB_GAP = 14
|
||||
TAB_BOTTOM_GAP = 26
|
||||
ACTION_PILL_WIDTH = 132
|
||||
DANGER_PILL_WIDTH = 112
|
||||
_TOPBAR_HEIGHT = 76.0
|
||||
@@ -138,7 +136,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
self._slider_specs: dict[str, dict[str, Any]] = {
|
||||
"ScreenBrightness": {
|
||||
"title": tr("Offroad Brightness"),
|
||||
"subtitle": tr("Primary screen brightness while parked."),
|
||||
"subtitle": "",
|
||||
"unit": "%",
|
||||
"labels": brightness_labels,
|
||||
"min": 0,
|
||||
@@ -151,7 +149,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
"ScreenBrightnessOnroad": {
|
||||
"title": tr("Onroad Brightness"),
|
||||
"subtitle": tr("Screen brightness while driving."),
|
||||
"subtitle": "",
|
||||
"unit": "%",
|
||||
"labels": brightness_labels,
|
||||
"min": 0,
|
||||
@@ -164,7 +162,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
"ScreenTimeout": {
|
||||
"title": tr("Offroad Screen Timeout"),
|
||||
"subtitle": tr("How long the display stays awake while parked."),
|
||||
"subtitle": "",
|
||||
"unit": "s",
|
||||
"labels": {},
|
||||
"min": 5,
|
||||
@@ -177,7 +175,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
"ScreenTimeoutOnroad": {
|
||||
"title": tr("Onroad Screen Timeout"),
|
||||
"subtitle": tr("How long the display stays on while driving."),
|
||||
"subtitle": "",
|
||||
"unit": "s",
|
||||
"labels": {},
|
||||
"min": 5,
|
||||
@@ -190,7 +188,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
"DeviceShutdown": {
|
||||
"title": tr("Shutdown Delay"),
|
||||
"subtitle": tr("How long the device waits before powering down."),
|
||||
"subtitle": "",
|
||||
"unit": "",
|
||||
"labels": shutdown_labels,
|
||||
"min": 0,
|
||||
@@ -203,7 +201,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
"LowVoltageShutdown": {
|
||||
"title": tr("Low Voltage Shutdown"),
|
||||
"subtitle": tr("Voltage threshold that protects the car battery."),
|
||||
"subtitle": "",
|
||||
"unit": "V",
|
||||
"labels": {},
|
||||
"min": 11.8,
|
||||
@@ -245,37 +243,37 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
self._toggle_defs = [
|
||||
{
|
||||
"title": tr("Standby Mode"),
|
||||
"subtitle": tr("Keep the device ready for faster wake-ups."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("StandbyMode"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("StandbyMode", v),
|
||||
},
|
||||
{
|
||||
"title": tr("Use Konik Server"),
|
||||
"subtitle": tr("Switch remote services to the Konik endpoint."),
|
||||
"subtitle": "",
|
||||
"get_state": self._controller._get_konik_state,
|
||||
"set_state": self._controller._on_konik_toggle,
|
||||
},
|
||||
{
|
||||
"title": tr("Debug Mode"),
|
||||
"subtitle": tr("Expose additional debugging and developer toggles."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("DebugMode"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("DebugMode", v),
|
||||
},
|
||||
{
|
||||
"title": tr("Show FPS"),
|
||||
"subtitle": tr("Display screen refresh rate and system performance metrics onroad."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("ShowFPS"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("ShowFPS", v),
|
||||
},
|
||||
{
|
||||
"title": tr("Disable Uploads"),
|
||||
"subtitle": tr("Stop all cloud uploads from this device."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("NoUploads"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("NoUploads", v),
|
||||
},
|
||||
{
|
||||
"title": tr("Disable Onroad Uploads"),
|
||||
"subtitle": tr("Block uploads while the car is onroad."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("DisableOnroadUploads"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("DisableOnroadUploads", v),
|
||||
"is_enabled": lambda: not self._controller._params.get_bool("NoUploads"),
|
||||
@@ -283,13 +281,13 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
},
|
||||
{
|
||||
"title": tr("Disable Logging"),
|
||||
"subtitle": tr("Stop writing standard log data to storage."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("NoLogging"),
|
||||
"set_state": lambda v: self._controller._params.put_bool("NoLogging", v),
|
||||
},
|
||||
{
|
||||
"title": tr("High Bitrate Recording"),
|
||||
"subtitle": tr("Capture higher-quality onroad footage."),
|
||||
"subtitle": "",
|
||||
"get_state": lambda: self._controller._params.get_bool("HigherBitrate"),
|
||||
"set_state": self._controller._on_higher_bitrate_toggle,
|
||||
"is_enabled": lambda: not self._controller._params.get_bool("DisableOnroadUploads") and not self._controller._params.get_bool("NoUploads"),
|
||||
@@ -299,7 +297,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
|
||||
self._basics_tile_grid_h = 0.0
|
||||
|
||||
self._connectivity_tile_grid = TileGrid(columns=2, padding=12, force_square=True, min_tile_height=130.0)
|
||||
self._connectivity_tile_grid = TileGrid(columns=2, padding=12, min_tile_height=130.0)
|
||||
for toggle_def in self._toggle_defs:
|
||||
tile = self._make_toggle_tile(toggle_def)
|
||||
self._connectivity_tile_grid.add_tile(tile)
|
||||
@@ -483,8 +481,9 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
self._scroll_rect.height = max(0.0, self._scroll_rect.height - total_offset)
|
||||
|
||||
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))
|
||||
hdr_h = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
display_h = self._slider_section_height(self._display_slider_keys, width) + 8 + hdr_h
|
||||
power_h = self._slider_section_height(self._power_slider_keys, width) + 8 + hdr_h
|
||||
|
||||
if self._uses_two_columns(width):
|
||||
column_w = self._column_width(width)
|
||||
@@ -497,7 +496,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
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)
|
||||
|
||||
left_overhead = 8.0 + 2 * (GROUP_HEADER_HEIGHT + GROUP_HEADER_GAP) + SECTION_GAP
|
||||
left_overhead = 8.0 + 2 * (GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP) + SECTION_GAP
|
||||
left_natural_content_h = left_overhead + display_container_h + power_container_h
|
||||
|
||||
tiles_content_h = self.measure_page_grid_height(self._connectivity_tile_grid, column_w - 24)
|
||||
@@ -516,7 +515,7 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
# Scale adjustors if needed
|
||||
if max_container_h < max_natural_h:
|
||||
scale_f = max_container_h / left_natural_content_h
|
||||
row_h = max(60.0, 94.0 * scale_f)
|
||||
row_h = max(80.0, float(AETHER_LIST_METRICS.adjustor_row_height) * scale_f)
|
||||
for key in self._display_slider_keys + self._power_slider_keys:
|
||||
self._adjustor_rows[key].custom_row_height = row_h
|
||||
|
||||
@@ -576,14 +575,14 @@ class SystemSettingsManagerView(PanelManagerView):
|
||||
self._render_page_grid(self._connectivity_tile_grid, 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)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
group_rect = rl.Rectangle(x, y, width, self._slider_section_height(keys, width))
|
||||
group_h = self._slider_section_height(keys, width) + 8 + GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
group_rect = rl.Rectangle(x, y, width, group_h)
|
||||
draw_list_group_shell(group_rect, style=PANEL_STYLE)
|
||||
current_y = group_rect.y
|
||||
current_y = group_rect.y + 8
|
||||
current_y = draw_group_header(x + 24, current_y, width - 48, title)
|
||||
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
|
||||
return y + group_h
|
||||
|
||||
def _draw_slider_row(self, rect: rl.Rectangle, key: str, is_last: bool) -> float:
|
||||
adjustor = self._adjustor_rows[key]
|
||||
|
||||
@@ -20,11 +20,12 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
PanelManagerView,
|
||||
SettingRow,
|
||||
TileGrid,
|
||||
GROUP_HEADER_GAP,
|
||||
GROUP_HEADER_HEIGHT,
|
||||
GROUP_HEADER_LINE_GAP,
|
||||
draw_group_header,
|
||||
draw_list_group_shell,
|
||||
draw_section_header,
|
||||
draw_settings_list_row,
|
||||
draw_subsection_header,
|
||||
SUBSECTION_OVERHEAD,
|
||||
)
|
||||
from openpilot.selfdrive.ui.lib.starpilot_state import starpilot_state
|
||||
from openpilot.selfdrive.ui.lib.fingerprint_catalog import (
|
||||
@@ -64,10 +65,8 @@ def _lock_doors_timer_labels():
|
||||
return labels
|
||||
|
||||
|
||||
SECTION_GAP = 16
|
||||
SECTION_HEADER_HEIGHT = 60
|
||||
SECTION_HEADER_GAP = 8
|
||||
ROW_HEIGHT = 86.0
|
||||
SECTION_GAP = 28
|
||||
ROW_HEIGHT = 125.0
|
||||
PANEL_STYLE = DEFAULT_PANEL_STYLE
|
||||
|
||||
|
||||
@@ -77,16 +76,13 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
outer_margin_y=14,
|
||||
panel_padding_top=16,
|
||||
panel_padding_bottom=14,
|
||||
section_header_height=60,
|
||||
section_header_gap=8,
|
||||
)
|
||||
|
||||
def __init__(self, controller: "StarPilotVehicleSettingsLayout"):
|
||||
super().__init__()
|
||||
self._controller = controller
|
||||
self._shell_rect = rl.Rectangle(0, 0, 0, 0)
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, force_square=True,
|
||||
min_tile_height=130.0)
|
||||
self._toggle_grid = TileGrid(columns=2, padding=12, min_tile_height=130.0)
|
||||
self.register_page_grid(self._toggle_grid)
|
||||
self._last_make = ""
|
||||
self._last_model = ""
|
||||
@@ -168,25 +164,26 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
value=value_text, enabled=enabled,
|
||||
hovered=hovered, pressed=pressed,
|
||||
is_last=is_last, show_chevron=row.on_click is not None,
|
||||
title_size=38, subtitle_size=26, value_size=32,
|
||||
style=PANEL_STYLE)
|
||||
title_size=49, subtitle_size=38, value_size=44,
|
||||
style=PANEL_STYLE)
|
||||
elif row.type == "toggle":
|
||||
toggle_value = row.get_state() if row.get_state else False
|
||||
draw_settings_list_row(rect, title=tr(row.title), subtitle=subtitle,
|
||||
toggle_value=toggle_value, enabled=enabled,
|
||||
hovered=hovered, pressed=pressed,
|
||||
is_last=is_last, show_chevron=False,
|
||||
title_size=38, subtitle_size=26,
|
||||
title_size=49, subtitle_size=38,
|
||||
style=PANEL_STYLE)
|
||||
|
||||
def _draw_section(self, y: float, x: float, width: float, title: str, rows: list[SettingRow], row_height: float = ROW_HEIGHT) -> float:
|
||||
if title:
|
||||
draw_section_header(rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT), tr(title), style=PANEL_STYLE)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
group_h = len(rows) * row_height
|
||||
hdr_oh = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
group_h = len(rows) * row_height + hdr_oh + 8
|
||||
draw_list_group_shell(rl.Rectangle(x, y, width, group_h), style=PANEL_STYLE)
|
||||
current_y = y + 8
|
||||
current_y = draw_group_header(x + 24, current_y, width - 48, tr(title))
|
||||
for i, row in enumerate(rows):
|
||||
self._draw_row(rl.Rectangle(x, y + i * row_height, width, row_height), row, i == len(rows) - 1)
|
||||
self._draw_row(rl.Rectangle(x, current_y, width, row_height), row, i == len(rows) - 1)
|
||||
current_y += row_height
|
||||
return y + group_h
|
||||
|
||||
def _draw_scroll_content(self, rect: rl.Rectangle, width: float):
|
||||
@@ -197,35 +194,28 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
if self._uses_two_columns(width):
|
||||
col_w = self._column_width(width)
|
||||
rx = rect.x + col_w + self.COLUMN_GAP
|
||||
content_y = y
|
||||
|
||||
# LEFT COLUMN
|
||||
draw_list_group_shell(rl.Rectangle(rect.x, content_y, col_w, self._container_h), style=PANEL_STYLE)
|
||||
row_y = content_y
|
||||
|
||||
# Vehicle Identity subsection header
|
||||
row_y = draw_subsection_header(rect.x + 24, row_y, col_w - 48, tr("Vehicle Identity"))
|
||||
|
||||
# All identity rows (Disable Fingerprinting, Car Make, Car Model, ...)
|
||||
draw_list_group_shell(rl.Rectangle(rect.x, y, col_w, self._container_h), style=PANEL_STYLE)
|
||||
row_y = y + 8
|
||||
row_y = draw_group_header(rect.x + 24, row_y, col_w - 48, tr("Vehicle Identity"))
|
||||
for i, row in enumerate(identity_rows):
|
||||
is_last = (i == len(identity_rows) - 1) and not steering_rows
|
||||
self._draw_row(rl.Rectangle(rect.x, row_y, col_w, self._left_row_height),
|
||||
row, is_last)
|
||||
row, i == len(identity_rows) - 1 and not steering_rows)
|
||||
row_y += self._left_row_height
|
||||
|
||||
# Steering Controls subsection header
|
||||
if steering_rows:
|
||||
row_y = draw_subsection_header(rect.x + 24, row_y, col_w - 48, tr("Steering Controls"))
|
||||
row_y = draw_group_header(rect.x + 24, row_y, col_w - 48, tr("STEERING CONTROLS"))
|
||||
for i, row in enumerate(steering_rows):
|
||||
self._draw_row(rl.Rectangle(rect.x, row_y, col_w, self._left_row_height),
|
||||
row, i == len(steering_rows) - 1)
|
||||
row_y += self._left_row_height
|
||||
|
||||
# RIGHT COLUMN — Feature subsection header inside tile group
|
||||
if self._toggle_grid.tiles:
|
||||
self._draw_two_column_tile_grid(self._toggle_grid, rx, content_y, col_w,
|
||||
self._container_h, title=None,
|
||||
subsection_title=tr("Feature"), style=PANEL_STYLE)
|
||||
draw_list_group_shell(rl.Rectangle(rx, y, col_w, self._container_h), style=PANEL_STYLE)
|
||||
tile_y = y + 8
|
||||
tile_y = draw_group_header(rx + 24, tile_y, col_w - 48, tr("Features"))
|
||||
avail_h = self._container_h - (tile_y - y)
|
||||
self._render_page_grid(self._toggle_grid, rl.Rectangle(rx + 12, tile_y, col_w - 24, max(0.0, avail_h - 12)))
|
||||
else:
|
||||
y = self._draw_section(y, rect.x, width, tr("Vehicle Identity"), identity_rows, self._left_row_height)
|
||||
y += SECTION_GAP
|
||||
@@ -233,14 +223,15 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
y += SECTION_GAP
|
||||
|
||||
if self._toggle_grid.tiles:
|
||||
draw_section_header(rl.Rectangle(rect.x, y, width, SECTION_HEADER_HEIGHT),
|
||||
tr("Features"), style=PANEL_STYLE)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
self._toggle_grid._columns = 3
|
||||
avail = width - 24
|
||||
th = self.measure_page_grid_height(self._toggle_grid, avail)
|
||||
draw_list_group_shell(rl.Rectangle(rect.x, y, width, th + 24), style=PANEL_STYLE)
|
||||
self._render_page_grid(self._toggle_grid, rl.Rectangle(rect.x + 12, y + 12, avail, th))
|
||||
hdr_oh = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
group_h = th + 24 + 8 + hdr_oh
|
||||
draw_list_group_shell(rl.Rectangle(rect.x, y, width, group_h), style=PANEL_STYLE)
|
||||
features_y = y + 8
|
||||
features_y = draw_group_header(rect.x + 24, features_y, width - 48, tr("Features"))
|
||||
self._render_page_grid(self._toggle_grid, rl.Rectangle(rect.x + 12, features_y, avail, max(0.0, group_h - (features_y - y) - 12)))
|
||||
|
||||
def _measure_content_height(self, width: float) -> float:
|
||||
self._check_rebuild_grid()
|
||||
@@ -259,9 +250,10 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
tiles_h = self.measure_page_grid_height(self._toggle_grid, width - 24)
|
||||
|
||||
if self._uses_two_columns(width):
|
||||
subsection_overhead = SUBSECTION_OVERHEAD
|
||||
hdr_oh = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
subsection_overhead = hdr_oh + 8
|
||||
if steering_rows:
|
||||
subsection_overhead += SUBSECTION_OVERHEAD
|
||||
subsection_overhead += hdr_oh
|
||||
|
||||
left_content_natural = total_rows * ROW_HEIGHT + subsection_overhead
|
||||
|
||||
@@ -280,10 +272,12 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
return total_h
|
||||
|
||||
self._left_row_height = ROW_HEIGHT
|
||||
identity_natural_h = self._section_block_height(self._section_height(len(identity_rows), ROW_HEIGHT))
|
||||
steering_natural_h = self._section_block_height(self._section_height(len(steering_rows), ROW_HEIGHT))
|
||||
hdr_oh = GROUP_HEADER_HEIGHT + GROUP_HEADER_LINE_GAP + GROUP_HEADER_GAP
|
||||
identity_natural_h = hdr_oh + 8 + len(identity_rows) * ROW_HEIGHT
|
||||
steering_natural_h = hdr_oh + 8 + len(steering_rows) * ROW_HEIGHT
|
||||
left_natural_h = identity_natural_h + SECTION_GAP + steering_natural_h
|
||||
return left_natural_h + tiles_h + (SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP if tiles_h else 0)
|
||||
tiles_overhead = 8 + hdr_oh + 24 if tiles_h else 0
|
||||
return left_natural_h + tiles_h + tiles_overhead
|
||||
|
||||
def _build_driving_toggles(self) -> list[dict]:
|
||||
cs = starpilot_state.car_state
|
||||
|
||||
@@ -41,7 +41,6 @@ class DeveloperSidebar:
|
||||
self._params = Params()
|
||||
self._font_bold = gui_app.font(FontWeight.SEMI_BOLD)
|
||||
self._last_toggles_check = 0.0
|
||||
self._cached_sidebar = False
|
||||
self._cached_metrics = [0] * 7
|
||||
self._cached_force_auto_tune_off = False
|
||||
self._cached_force_auto_tune = False
|
||||
@@ -81,7 +80,6 @@ class DeveloperSidebar:
|
||||
if now - self._last_toggles_check < 1.0:
|
||||
return
|
||||
self._last_toggles_check = now
|
||||
self._cached_sidebar = self._params.get_bool("DeveloperSidebar")
|
||||
self._cached_metrics = [self._params.get_int(f"DeveloperSidebarMetric{i}") for i in range(1, 8)]
|
||||
self._cached_force_auto_tune_off = self._params.get_bool("ForceAutoTuneOff")
|
||||
self._cached_force_auto_tune = self._params.get_bool("ForceAutoTune")
|
||||
@@ -128,10 +126,10 @@ class DeveloperSidebar:
|
||||
def update(self):
|
||||
self._refresh_cache()
|
||||
|
||||
self._visible = (
|
||||
self._cached_sidebar or
|
||||
ui_state.starpilot_toggles.get("developer_sidebar", False)
|
||||
)
|
||||
# ---- PC REPLAY FALLBACK (remove the next line when replay gets toggle bridge) ----
|
||||
# self._visible = ui_state.starpilot_toggles.get("developer_sidebar", False)
|
||||
# ---- replace the line below with the one above ---->
|
||||
self._visible = self._params.get("DeveloperSidebar") or False or ui_state.starpilot_toggles.get("developer_sidebar", False)
|
||||
if not self._visible:
|
||||
return
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ class PersonalityButton(Widget):
|
||||
|
||||
self.set_visible(lambda: ui_state.started and ui_state.has_longitudinal_control)
|
||||
|
||||
@property
|
||||
def center_x(self) -> float:
|
||||
return self._rect.x + self._rect.width / 2
|
||||
|
||||
@property
|
||||
def is_interacting(self) -> bool:
|
||||
return self.is_pressed
|
||||
|
||||
@@ -60,12 +60,15 @@ class StarPilotOnroadView(AugmentedRoadView):
|
||||
self._render_standstill_timer()
|
||||
self._render_developer_metrics()
|
||||
dm = self.driver_state_renderer
|
||||
if dm and dm.is_visible and dm.position_x != 0.0:
|
||||
dm_top = dm.position_y - 96 # top of DM icon
|
||||
if dm and dm.position_x != 0.0:
|
||||
cx = dm.position_x
|
||||
btn = self._personality_button
|
||||
if btn.is_visible and btn.center_x < cx:
|
||||
cx = btn.center_x
|
||||
self._aethergauge.render(
|
||||
self._content_rect, self._font_bold, self._font_medium,
|
||||
current_speed=self._hud_renderer.speed,
|
||||
cx=dm.position_x, bottom=dm_top - 105
|
||||
cx=cx, bottom=dm.position_y - 96 - 145
|
||||
)
|
||||
else:
|
||||
self._aethergauge.render(self._content_rect, self._font_bold, self._font_medium, current_speed=self._hud_renderer.speed)
|
||||
|
||||
Reference in New Issue
Block a user