BigUI WIP: Meet The Parents

This commit is contained in:
firestarsdog
2026-07-01 01:52:11 -04:00
parent 4bb15dded4
commit f40881657c
4 changed files with 206 additions and 87 deletions
@@ -2952,6 +2952,14 @@ class SettingSection:
row_height: int = ROW_HEIGHT
@dataclass
class ParentToggle:
label: str
get_state: Callable[[], bool]
set_state: Callable[[bool], None]
subtitle: str = ""
# ── AetherSettingsView — reusable list-panel ManagerView ──
class AetherSettingsView(PanelManagerView):
@@ -2965,6 +2973,7 @@ class AetherSettingsView(PanelManagerView):
def __init__(self, controller, sections: list[SettingSection],
*, header_title: str = "", header_subtitle: str = "",
parent_toggle: ParentToggle | None = None,
tab_defs: list[dict] | None = None,
panel_style=None, fade_height: float = AETHER_LIST_METRICS.fade_height,
metrics = COMPACT_PANEL_METRICS):
@@ -2976,7 +2985,8 @@ class AetherSettingsView(PanelManagerView):
self._sections = sections
self._header_title = header_title
self._header_subtitle = header_subtitle
self._has_header = bool(header_title)
self._parent_toggle = parent_toggle
self._has_header = bool(header_title) or parent_toggle is not None
self._tab_defs = tab_defs
self._active_tab_key = tab_defs[0]["id"] if tab_defs else ""
self._scroll_panel = GuiScrollPanel2(horizontal=False)
@@ -2992,9 +3002,20 @@ class AetherSettingsView(PanelManagerView):
return row
return None
def _target_at(self, mouse_pos: MousePos) -> str | None:
if self._parent_toggle:
mid = f"parent_toggle:{self._parent_toggle.label}"
rect = self._interactive_rects.get(mid)
if rect and point_hits(mouse_pos, rect, None, pad_x=6, pad_y=6):
return mid
return super()._target_at(mouse_pos)
def _activate_target(self, target_id: str | None):
if not target_id:
return
if target_id.startswith("parent_toggle:") and self._parent_toggle:
self._parent_toggle.set_state(not self._parent_toggle.get_state())
return
if target_id.startswith("tab:") and self._tab_defs:
self._active_tab_key = target_id[4:]
return
@@ -3013,6 +3034,19 @@ class AetherSettingsView(PanelManagerView):
def _compute_header_height(self, content_width: float) -> float:
if not self._has_header:
return 0.0
if self._parent_toggle:
h = max(42.0, 40.0) # toggle (42px at header top) vs title area (32px + 8px gap)
subtitle_text = tr(self._parent_toggle.subtitle) if self._parent_toggle.subtitle else ""
if self._header_subtitle:
subtitle_text = tr(self._header_subtitle)
if subtitle_text:
toggle_take = AETHER_LIST_METRICS.toggle_width + AETHER_LIST_METRICS.toggle_right_inset + 16
col_w = max(100.0, content_width + AETHER_LIST_METRICS.content_right_gutter - toggle_take)
desc_font = gui_app.font(FontWeight.NORMAL)
desc_lines = wrap_text(desc_font, subtitle_text, col_w, 18, max_lines=4)
h += len(desc_lines) * 22.0 + 12.0
h += SECTION_GAP
return h
h = 40.0 # title (32px) + inner gap (8px)
if self._header_subtitle:
subtitle_text = tr(self._header_subtitle)
@@ -3066,7 +3100,42 @@ class AetherSettingsView(PanelManagerView):
def _draw_header(self, rect: rl.Rectangle):
title = tr(self._header_title) if self._header_title else ""
subtitle = tr(self._header_subtitle) if self._header_subtitle else ""
draw_settings_panel_header(rect, title, subtitle, title_size=32, subtitle_size=18)
if self._parent_toggle:
toggle = self._parent_toggle
display_title = title if title else tr(toggle.label)
subtitle_text = subtitle if subtitle else (tr(toggle.subtitle) if toggle.subtitle else "")
toggle_take = AETHER_LIST_METRICS.toggle_width + AETHER_LIST_METRICS.toggle_right_inset + 16
text_rect = rl.Rectangle(rect.x, rect.y, max(100.0, rect.width - toggle_take), rect.height)
draw_settings_panel_header(text_rect, display_title, subtitle_text, title_size=32, subtitle_size=18)
toggle_id = f"parent_toggle:{toggle.label}"
tw = AETHER_LIST_METRICS.toggle_width
th = AETHER_LIST_METRICS.toggle_height
ri = AETHER_LIST_METRICS.toggle_right_inset
toggle_rect = rl.Rectangle(rect.x + rect.width - tw - ri, rect.y, tw, th)
self._interactive_rects[toggle_id] = toggle_rect
toggle_value = toggle.get_state()
target_progress = 1.0 if toggle_value else 0.0
current_progress = _KNOB_ANIMATION_STATES.get(toggle_id, target_progress)
dt = rl.get_frame_time()
current_progress += (target_progress - current_progress) * 12.0 * dt
if abs(current_progress - target_progress) < 0.001:
current_progress = target_progress
_KNOB_ANIMATION_STATES[toggle_id] = current_progress
draw_toggle_switch(
rl.Rectangle(rect.x, rect.y, rect.width, th),
toggle_value,
knob_progress=current_progress,
track_color=self._panel_style.accent,
seed_id=toggle_id,
)
else:
draw_settings_panel_header(rect, title, subtitle, title_size=32, subtitle_size=18)
def _active_sections(self) -> list[SettingSection]:
if self._tab_defs and self._active_tab_key:
@@ -3129,12 +3198,20 @@ class AetherSettingsView(PanelManagerView):
active = self._active_sections()
has_visible = any(self._visible_rows(s) for s in active)
if not has_visible:
draw_empty_state_card(
rl.Rectangle(rect.x, y, width, rect.height - (y - rect.y)),
tr("No settings to display"),
tr("All options in this panel are hidden or unavailable."),
style=self._panel_style,
)
if self._parent_toggle and not self._parent_toggle.get_state():
draw_empty_state_card(
rl.Rectangle(rect.x, y, width, rect.height - (y - rect.y)),
tr("Enable {} to configure settings.").format(tr(self._parent_toggle.label)),
"",
style=self._panel_style,
)
elif not self._parent_toggle:
draw_empty_state_card(
rl.Rectangle(rect.x, y, width, rect.height - (y - rect.y)),
tr("No settings to display"),
tr("All options in this panel are hidden or unavailable."),
style=self._panel_style,
)
return
i = 0
while i < len(active):
@@ -15,6 +15,7 @@ import pyray as rl
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
AetherSliderDialog,
DEFAULT_PANEL_STYLE,
ParentToggle,
SettingRow,
SettingSection,
AetherSettingsView,
@@ -177,6 +178,14 @@ class StarPilotAppearanceLayout(_SettingsPage):
super().__init__()
self._build_view()
def _make_parent(self, key: str, label: str, subtitle: str = "") -> ParentToggle:
return ParentToggle(
label=label,
subtitle=subtitle,
get_state=lambda k=key: self._params.get_bool(k),
set_state=lambda s, k=key: self._params.put_bool(k, s),
)
def _show_lead_detection_threshold_selector(self):
def on_close(res, val):
if res == DialogResult.CONFIRM:
@@ -197,127 +206,146 @@ class StarPilotAppearanceLayout(_SettingsPage):
po = lambda: self._params.get_bool("PedalsOnUI")
ol = lambda: starpilot_state.car_state.hasOpenpilotLongitudinal
bsm = lambda: starpilot_state.car_state.hasBSM
model_on = lambda: self._params.get_bool("ModelUI")
hud_on = lambda: self._params.get_bool("CustomUI")
# ═══ 1. Model & Path Visualization ═══
self._model_rows = [
SettingRow("ModelUI", "toggle", tr_noop("Model UI"),
subtitle=tr_noop("Display the driving model path, lanes, and road edges."),
get_state=lambda: self._params.get_bool("ModelUI"),
set_state=lambda s: self._params.put_bool("ModelUI", s)),
SettingRow("DynamicPathWidth", "toggle", tr_noop("Dynamic Path"),
subtitle="",
get_state=lambda: self._params.get_bool("DynamicPathWidth"),
set_state=lambda s: self._params.put_bool("DynamicPathWidth", s)),
set_state=lambda s: self._params.put_bool("DynamicPathWidth", s),
visible=model_on),
SettingRow("LaneLinesWidth", "value", tr_noop("Lane Line Width"),
subtitle="",
get_value=self._get_lane_lines_display,
on_click=lambda: self._show_int_selector("LaneLinesWidth", 0, 24, self._get_lane_lines_unit())),
on_click=lambda: self._show_int_selector("LaneLinesWidth", 0, 24, self._get_lane_lines_unit()),
visible=model_on),
SettingRow("LaneLinesColor", "value", tr_noop("Lane Line Color"),
subtitle="",
get_value=lambda: self._get_color_display("LaneLinesColor"),
on_click=lambda: self._show_color_selector("LaneLinesColor")),
on_click=lambda: self._show_color_selector("LaneLinesColor"),
visible=model_on),
SettingRow("PathWidth", "value", tr_noop("Path Width"),
subtitle="",
get_value=self._get_path_width_display,
on_click=self._show_path_width_selector),
on_click=self._show_path_width_selector,
visible=model_on),
SettingRow("PathEdgeWidth", "value", tr_noop("Path Edge Width"),
subtitle="",
get_value=lambda: f"{self._params.get_int('PathEdgeWidth')}%",
on_click=lambda: self._show_int_selector("PathEdgeWidth", 0, 100, "%")),
on_click=lambda: self._show_int_selector("PathEdgeWidth", 0, 100, "%"),
visible=model_on),
SettingRow("PathEdgesColor", "value", tr_noop("Path Edge Color"),
subtitle="",
get_value=lambda: self._get_color_display("PathEdgesColor"),
on_click=lambda: self._show_color_selector("PathEdgesColor")),
on_click=lambda: self._show_color_selector("PathEdgesColor"),
visible=model_on),
SettingRow("PathColor", "value", tr_noop("Path Color"),
subtitle="",
get_value=lambda: self._get_color_display("PathColor"),
on_click=lambda: self._show_color_selector("PathColor")),
on_click=lambda: self._show_color_selector("PathColor"),
visible=model_on),
SettingRow("RoadEdgesWidth", "value", tr_noop("Road Edge Width"),
subtitle="",
get_value=self._get_road_edges_display,
on_click=lambda: self._show_int_selector("RoadEdgesWidth", 0, 24, self._get_road_edges_unit())),
on_click=lambda: self._show_int_selector("RoadEdgesWidth", 0, 24, self._get_road_edges_unit()),
visible=model_on),
SettingRow("RainbowPath", "toggle", tr_noop("Rainbow Path"),
subtitle="",
get_state=lambda: self._params.get_bool("RainbowPath"),
set_state=lambda s: self._params.put_bool("RainbowPath", s)),
set_state=lambda s: self._params.put_bool("RainbowPath", s),
visible=model_on),
SettingRow("AccelerationPath", "toggle", tr_noop("Acceleration Path"),
subtitle="",
get_state=lambda: self._params.get_bool("AccelerationPath"),
set_state=lambda s: self._params.put_bool("AccelerationPath", s),
enabled=ol),
enabled=ol,
visible=model_on),
SettingRow("AdjacentPath", "toggle", tr_noop("Adjacent Lanes"),
subtitle="",
get_state=lambda: self._params.get_bool("AdjacentPath"),
set_state=lambda s: self._params.put_bool("AdjacentPath", s)),
set_state=lambda s: self._params.put_bool("AdjacentPath", s),
visible=model_on),
SettingRow("AdjacentPathMetrics", "toggle", tr_noop("Adjacent Lane Metrics"),
subtitle="",
get_state=lambda: self._params.get_bool("AdjacentPathMetrics"),
set_state=lambda s: self._params.put_bool("AdjacentPathMetrics", s)),
set_state=lambda s: self._params.put_bool("AdjacentPathMetrics", s),
visible=model_on),
SettingRow("BlindSpotPath", "toggle", tr_noop("Blind Spot Path"),
subtitle="",
get_state=lambda: self._params.get_bool("BlindSpotPath"),
set_state=lambda s: self._params.put_bool("BlindSpotPath", s),
enabled=bsm),
enabled=bsm,
visible=model_on),
]
# ═══ 2. Driving Widgets & HUD ═══
self._hud_rows = [
SettingRow("CustomUI", "toggle", tr_noop("Driving Screen Widgets"),
subtitle=tr_noop("Show interactive indicators on the driving screen."),
get_state=lambda: self._params.get_bool("CustomUI"),
set_state=lambda s: self._params.put_bool("CustomUI", s)),
SettingRow("Compass", "toggle", tr_noop("Compass"),
subtitle="",
get_state=lambda: self._params.get_bool("Compass"),
set_state=lambda s: self._params.put_bool("Compass", s)),
set_state=lambda s: self._params.put_bool("Compass", s),
visible=hud_on),
SettingRow("OnroadDistanceButton", "toggle", tr_noop("Personality Button"),
subtitle="",
get_state=lambda: self._params.get_bool("OnroadDistanceButton"),
set_state=lambda s: self._params.put_bool("OnroadDistanceButton", s)),
set_state=lambda s: self._params.put_bool("OnroadDistanceButton", s),
visible=hud_on),
SettingRow("RotatingWheel", "toggle", tr_noop("Rotating Wheel"),
subtitle="",
get_state=lambda: self._params.get_bool("RotatingWheel"),
set_state=lambda s: self._params.put_bool("RotatingWheel", s)),
set_state=lambda s: self._params.put_bool("RotatingWheel", s),
visible=hud_on),
SettingRow("ShowSteering", "toggle", tr_noop("Steering Torque Indicator"),
subtitle="",
get_state=lambda: self._params.get_bool("ShowSteering"),
set_state=lambda s: self._params.put_bool("ShowSteering", s)),
set_state=lambda s: self._params.put_bool("ShowSteering", s),
visible=hud_on),
SettingRow("SignalMetrics", "toggle", tr_noop("Turn Signal Borders"),
subtitle="",
get_state=lambda: self._params.get_bool("SignalMetrics"),
set_state=lambda s: self._params.put_bool("SignalMetrics", s)),
set_state=lambda s: self._params.put_bool("SignalMetrics", s),
visible=hud_on),
SettingRow("BlindSpotMetrics", "toggle", tr_noop("Blind Spot Borders"),
subtitle="",
get_state=lambda: self._params.get_bool("BlindSpotMetrics"),
set_state=lambda s: self._params.put_bool("BlindSpotMetrics", s),
enabled=bsm),
enabled=bsm,
visible=hud_on),
SettingRow("WheelSpeed", "toggle", tr_noop("Wheel Speed"),
subtitle="",
get_state=lambda: self._params.get_bool("WheelSpeed"),
set_state=lambda s: self._params.put_bool("WheelSpeed", s)),
set_state=lambda s: self._params.put_bool("WheelSpeed", s),
visible=hud_on),
SettingRow("BorderWidth", "value", tr_noop("Border Width"),
subtitle="",
get_value=lambda: f"{int(round(self._params.get_float('BorderWidth')))}%",
on_click=lambda: self._show_float_selector("BorderWidth", 25, 250, 5, "%")),
on_click=lambda: self._show_float_selector("BorderWidth", 25, 250, 5, "%"),
visible=hud_on),
SettingRow("PedalsOnUI", "toggle", tr_noop("Pedal Indicators"),
subtitle="",
get_state=lambda: self._params.get_bool("PedalsOnUI"),
set_state=lambda s: self._params.put_bool("PedalsOnUI", s),
enabled=ol),
enabled=ol,
visible=hud_on),
SettingRow("DynamicPedalsOnUI", "toggle", tr_noop("Dynamic Pedals"),
subtitle="",
get_state=lambda: self._params.get_bool("DynamicPedalsOnUI"),
set_state=lambda s: self._set_exclusive_pedal("DynamicPedalsOnUI", "StaticPedalsOnUI", s),
enabled=lambda: po() and ol()),
enabled=lambda: po() and ol(),
visible=hud_on),
SettingRow("StaticPedalsOnUI", "toggle", tr_noop("Static Pedals"),
subtitle="",
get_state=lambda: self._params.get_bool("StaticPedalsOnUI"),
set_state=lambda s: self._set_exclusive_pedal("StaticPedalsOnUI", "DynamicPedalsOnUI", s),
enabled=lambda: po() and ol()),
enabled=lambda: po() and ol(),
visible=hud_on),
SettingRow("StoppedTimer", "toggle", tr_noop("Stopped Timer"),
subtitle="",
get_state=lambda: self._params.get_bool("StoppedTimer"),
set_state=lambda s: self._params.put_bool("StoppedTimer", s)),
set_state=lambda s: self._params.put_bool("StoppedTimer", s),
visible=hud_on),
]
# ═══ 3. Screen Declutter & Visibility ═══
@@ -461,12 +489,18 @@ class StarPilotAppearanceLayout(_SettingsPage):
panel_style=PANEL_STYLE,
)
pt_model = self._make_parent("ModelUI", "Model UI",
"Display the driving model path, lanes, and road edges.")
pt_hud = self._make_parent("CustomUI", "Driving Screen Widgets",
"Show interactive indicators on the driving screen.")
# Register subpanels for Level 2 slide transitions
self._sub_panels["model"] = AetherSettingsView(
self,
[SettingSection(title="", rows=self._model_rows)],
header_title=tr_noop("Model & Path Visualization"),
header_subtitle=tr_noop("Customize dynamic lane paths, road edges, and colors."),
parent_toggle=pt_model,
panel_style=PANEL_STYLE,
)
self._sub_panels["hud"] = AetherSettingsView(
@@ -474,6 +508,7 @@ class StarPilotAppearanceLayout(_SettingsPage):
[SettingSection(title="", rows=self._hud_rows)],
header_title=tr_noop("Driving Widgets & HUD"),
header_subtitle=tr_noop("Configure compass, dynamic pedals, signals, and screen borders."),
parent_toggle=pt_hud,
panel_style=PANEL_STYLE,
)
self._sub_panels["declutter"] = AetherSettingsView(
@@ -13,6 +13,7 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import _SettingsPag
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
DEFAULT_PANEL_STYLE,
AetherSettingsView,
ParentToggle,
SettingRow,
SettingSection,
TileGrid,
@@ -140,6 +141,14 @@ class StarPilotLateralLayout(_SettingsPage):
super().__init__()
self._build_panels()
def _make_parent(self, key: str, label: str, subtitle: str = "") -> ParentToggle:
return ParentToggle(
label=label,
subtitle=subtitle,
get_state=lambda k=key: self._params.get_bool(k),
set_state=lambda s, k=key: self._params.put_bool(k, s),
)
def _build_panels(self):
p = self._params
cs = starpilot_state.car_state
@@ -161,12 +170,6 @@ class StarPilotLateralLayout(_SettingsPage):
# ── 1. Steering Behavior ──
self._behavior_rows = [
SettingRow(
"AlwaysOnLateral", "toggle", tr_noop("Always On Lateral"),
subtitle=tr_noop("Steering stays active when ACC is off."),
get_state=lambda: p.get_bool("AlwaysOnLateral"),
set_state=lambda s: _confirm_reboot_toggle(p, "AlwaysOnLateral", s) if s else p.put_bool("AlwaysOnLateral", False),
),
SettingRow(
"PauseAOLOnBrake", "value", tr_noop("Pause AOL On Brake"),
subtitle=tr_noop("Pause AOL below this speed while brake is pressed."),
@@ -203,12 +206,6 @@ class StarPilotLateralLayout(_SettingsPage):
# ── 2. Lane Changes ──
self._lane_change_rows = [
SettingRow(
"LaneChanges", "toggle", tr_noop("Lane Changes"),
subtitle=tr_noop("Allow openpilot to change lanes."),
get_state=lambda: p.get_bool("LaneChanges"),
set_state=lambda s: p.put_bool("LaneChanges", s),
),
SettingRow(
"NudgelessLaneChange", "toggle", tr_noop("Auto Lane Changes"),
subtitle=tr_noop("Signal triggers automatic lane change."),
@@ -255,12 +252,6 @@ class StarPilotLateralLayout(_SettingsPage):
# ── 3. Advanced Lateral Tuning ──
self._advanced_rows = [
SettingRow(
"AdvancedLateralTune", "toggle", tr_noop("Advanced Lateral Tuning"),
subtitle=tr_noop("Fine-tune steering response and auto-tuning."),
get_state=lambda: p.get_bool("AdvancedLateralTune"),
set_state=lambda s: p.put_bool("AdvancedLateralTune", s),
),
SettingRow(
"NNFF", "toggle", tr_noop("NNFF"),
subtitle=tr_noop("Neural net feedforward steering controller."),
@@ -365,12 +356,25 @@ class StarPilotLateralLayout(_SettingsPage):
header_subtitle=tr_noop("Configure steering behavior and lane changes."),
)
p = self._params
pt_behavior = ParentToggle(
label="Always On Lateral",
subtitle="Steering stays active when ACC is off.",
get_state=lambda: p.get_bool("AlwaysOnLateral"),
set_state=lambda s: _confirm_reboot_toggle(p, "AlwaysOnLateral", s) if s else p.put_bool("AlwaysOnLateral", False),
)
pt_lane_changes = self._make_parent("LaneChanges", "Lane Changes",
"Allow openpilot to change lanes.")
pt_advanced = self._make_parent("AdvancedLateralTune", "Advanced Lateral Tuning",
"Fine-tune steering response and auto-tuning.")
# Register subpanels for Level 2 slide transitions
self._sub_panels["behavior"] = AetherSettingsView(
self,
[SettingSection(title="", rows=self._behavior_rows)],
header_title=tr_noop("Steering Behavior"),
header_subtitle=tr_noop("Configure Always On Lateral (AOL), pause speed thresholds, and turn signal behaviors."),
parent_toggle=pt_behavior,
panel_style=PANEL_STYLE,
)
self._sub_panels["lane_changes"] = AetherSettingsView(
@@ -378,6 +382,7 @@ class StarPilotLateralLayout(_SettingsPage):
[SettingSection(title="", rows=self._lane_change_rows)],
header_title=tr_noop("Lane Changes"),
header_subtitle=tr_noop("Configure automatic lane changes, speed/width thresholds, and smoothing parameters."),
parent_toggle=pt_lane_changes,
panel_style=PANEL_STYLE,
)
self._sub_panels["advanced"] = AetherSettingsView(
@@ -385,6 +390,7 @@ class StarPilotLateralLayout(_SettingsPage):
[SettingSection(title="", rows=self._advanced_rows)],
header_title=tr_noop("Advanced Lateral Tuning"),
header_subtitle=tr_noop("Adjust actuator delay, steer ratio, Kp, friction, and neural network feedforward controllers."),
parent_toggle=pt_advanced,
panel_style=PANEL_STYLE,
)
self._wire_sub_panels()
@@ -19,6 +19,7 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
AETHER_LIST_METRICS,
AetherSliderDialog,
DEFAULT_PANEL_STYLE,
ParentToggle,
SettingRow,
SettingSection,
AetherSettingsView,
@@ -249,6 +250,14 @@ class StarPilotLongitudinalLayout(_SettingsPage):
def _show_stop_tuning_values(self) -> bool:
return self._advanced_enabled() and not (starpilot_state.car_state.isToyota and self._params.get_bool("FrogsGoMoosTweak"))
def _make_parent(self, key: str, label: str, subtitle: str = "") -> ParentToggle:
return ParentToggle(
label=label,
subtitle=subtitle,
get_state=lambda k=key: self._params.get_bool(k),
set_state=lambda s, k=key: self._params.put_bool(k, s),
)
def _build_view(self):
ol = lambda: starpilot_state.car_state.hasOpenpilotLongitudinal
ce_on = lambda: self._params.get_bool("ConditionalExperimental")
@@ -258,10 +267,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 1. Longitudinal Tuning Rows ──
self._tune_rows = [
SettingRow("LongitudinalTune", "toggle", tr_noop("Longitudinal Tuning"),
subtitle=tr_noop("Acceleration and braking control changes to fine-tune how openpilot drives."),
get_state=lambda: self._params.get_bool("LongitudinalTune"),
set_state=lambda s: self._params.put_bool("LongitudinalTune", s)),
SettingRow("AccelProfile", "value", tr_noop("Acceleration Profile"),
subtitle=tr_noop("Choose how quickly openpilot speeds up."),
get_value=self._get_acceleration_profile_label,
@@ -297,10 +302,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 2. Advanced Actuators Rows ──
adv = self._advanced_enabled
self._advanced_rows = [
SettingRow("AdvancedLongitudinalTune", "toggle", tr_noop("Advanced Longitudinal Tuning"),
subtitle=tr_noop("Advanced acceleration and braking changes for refining launch, stopping, and actuator response."),
get_state=lambda: self._params.get_bool("AdvancedLongitudinalTune"),
set_state=lambda s: self._params.put_bool("AdvancedLongitudinalTune", s)),
SettingRow("EVTuning", "toggle", tr_noop("EV Tuning"),
subtitle=tr_noop("Acceleration tuning for EV and direct-drive vehicles."),
get_state=lambda: self._params.get_bool("EVTuning"),
@@ -359,10 +360,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 3. Speed Limit Controller (SLC) Rows ──
self._slc_rows = [
SettingRow("SLC", "toggle", tr_noop("Speed Limit Controller"),
subtitle=tr_noop("Limit the car's maximum speed to the current speed limit."),
get_state=lambda: self._params.get_bool("SpeedLimitController"),
set_state=lambda s: self._params.put_bool("SpeedLimitController", s)),
SettingRow("SLCFallback", "value", tr_noop("Fallback Speed"),
subtitle="",
get_value=lambda: self._params.get("SLCFallback", encoding="utf-8") or "Set Speed",
@@ -436,10 +433,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 4. Adaptive Speed Controls Rows (CES + CSC) ──
self._conditional_experimental_rows = [
SettingRow("ConditionalExperimental", "toggle", tr_noop("Conditional Experimental Mode"),
subtitle="",
get_state=lambda: self._params.get_bool("ConditionalExperimental"),
set_state=lambda s: self._params.put_bool("ConditionalExperimental", s)),
SettingRow("PersistExp", "toggle", tr_noop("Persist Experimental State"),
subtitle=tr_noop("Keep override through reboots until manually cleared."),
get_state=lambda: self._params.get_bool("PersistExperimentalState"),
@@ -508,10 +501,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
]
self._curve_speed_controller_rows = [
SettingRow("CurveSpeed", "toggle", tr_noop("Curve Speed Controller"),
subtitle="",
get_state=lambda: self._params.get_bool("CurveSpeedController"),
set_state=lambda s: self._params.put_bool("CurveSpeedController", s)),
SettingRow("ShowCSCStatus", "toggle", tr_noop("Status Widget"),
subtitle=tr_noop("Show the Curve Speed Controller ambient effect on the driving screen."),
get_state=lambda: self._params.get_bool("ShowCSCStatus"),
@@ -537,10 +526,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 5. Driving Personalities Rows ──
self._personality_rows = [
SettingRow("PersonalitiesToggle", "toggle", tr_noop("Driving Personalities"),
subtitle="",
get_state=lambda: self._params.get_bool("CustomPersonalities"),
set_state=lambda s: self._params.put_bool("CustomPersonalities", s)),
SettingRow("Traffic", "value", tr_noop("Traffic"),
subtitle=tr_noop("Configure follow distance, smoothness, and response for traffic conditions."),
get_value=lambda: tr_noop("Configure"),
@@ -561,10 +546,6 @@ class StarPilotLongitudinalLayout(_SettingsPage):
# ── 6. Daily QOL & Weather Rows ──
self._daily_rows = [
SettingRow("QOLToggle", "toggle", tr_noop("Quality of Life"),
subtitle="",
get_state=lambda: self._params.get_bool("QOLLongitudinal"),
set_state=lambda s: self._params.put_bool("QOLLongitudinal", s)),
SettingRow("CustomCruise", "value", tr_noop("Cruise Interval"),
subtitle="",
get_value=lambda: f"{max(1, self._params.get_int('CustomCruise'))} mph",
@@ -661,6 +642,19 @@ class StarPilotLongitudinalLayout(_SettingsPage):
panel_style=PANEL_STYLE,
)
pt_tune = self._make_parent("LongitudinalTune", "Longitudinal Tuning",
"Acceleration and braking control changes to fine-tune how openpilot drives.")
pt_advanced = self._make_parent("AdvancedLongitudinalTune", "Advanced Longitudinal Tuning",
"Advanced acceleration and braking changes for refining launch, stopping, and actuator response.")
pt_personality = self._make_parent("CustomPersonalities", "Driving Personalities")
pt_daily = self._make_parent("QOLLongitudinal", "Quality of Life")
pt_slc = self._make_parent("SpeedLimitController", "Speed Limit Controller",
"Limit the car's maximum speed to the current speed limit.")
pt_ce = self._make_parent("ConditionalExperimental", "Conditional Experimental",
"Configure triggers and threshold speeds for automated Experimental Mode switching.")
pt_csc = self._make_parent("CurveSpeedController", "Curve Speed Controller",
"Configure speed control on curves and reset collected calibration data.")
ce_rows = self._conditional_experimental_rows
self._sub_panels["ce"] = AetherSettingsView(
self,
@@ -670,6 +664,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
],
header_title=tr("Conditional Experimental"),
header_subtitle=tr("Configure triggers and threshold speeds for automated Experimental Mode switching."),
parent_toggle=pt_ce,
panel_style=PANEL_STYLE,
)
@@ -682,6 +677,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
],
header_title=tr("Curve Speed Controller"),
header_subtitle=tr("Configure speed control on curves and reset collected calibration data."),
parent_toggle=pt_csc,
panel_style=PANEL_STYLE,
)
@@ -693,6 +689,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
[SettingSection(title="", rows=self._tune_rows)],
header_title=tr_noop("Longitudinal Tuning"),
header_subtitle=tr_noop("Configure acceleration profiles, smooth following, lane changes, and route speed control."),
parent_toggle=pt_tune,
panel_style=PANEL_STYLE,
)
self._sub_panels["advanced"] = AetherSettingsView(
@@ -700,6 +697,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
[SettingSection(title="", rows=self._advanced_rows)],
header_title=tr_noop("Advanced Actuators"),
header_subtitle=tr_noop("Adjust actuator delay, EV/Truck tuning, and launch/stop speeds/rates."),
parent_toggle=pt_advanced,
panel_style=PANEL_STYLE,
)
self._sub_panels["slc"] = AetherSettingsView(
@@ -707,6 +705,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
[SettingSection(title="", rows=self._slc_rows)],
header_title=tr_noop("Speed Limit Controller"),
header_subtitle=tr_noop("Manage auto speed matching, confirmation, offsets, and source priority."),
parent_toggle=pt_slc,
panel_style=PANEL_STYLE,
)
self._sub_panels["personality"] = AetherSettingsView(
@@ -714,6 +713,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
[SettingSection(title="", rows=self._personality_rows)],
header_title=tr_noop("Driving Personalities"),
header_subtitle=tr_noop("Customize follow distance and jerk/response metrics for each personality profile."),
parent_toggle=pt_personality,
panel_style=PANEL_STYLE,
)
self._sub_panels["daily"] = AetherSettingsView(
@@ -721,6 +721,7 @@ class StarPilotLongitudinalLayout(_SettingsPage):
[SettingSection(title="", rows=self._daily_rows)],
header_title=tr_noop("Daily QOL & Weather"),
header_subtitle=tr_noop("Configure cruise intervals, standstill behaviors, gear mapping, and weather presets."),
parent_toggle=pt_daily,
panel_style=PANEL_STYLE,
)
self._wire_sub_panels()