ui: add driving personality selector to settings (#35524)

* Add driving personality selector to settings

* icon

* format

* type

---------

Co-authored-by: Shane Smiskol <shane@smiskol.com>
This commit is contained in:
Dean Lee
2025-06-12 12:18:07 +08:00
committed by GitHub
parent 58763f4551
commit 79319d2447
2 changed files with 77 additions and 1 deletions
+18 -1
View File
@@ -1,4 +1,4 @@
from openpilot.system.ui.lib.list_view import ListView, toggle_item
from openpilot.system.ui.lib.list_view import ListView, multiple_button_item, toggle_item
from openpilot.system.ui.lib.widget import Widget
from openpilot.common.params import Params
@@ -9,6 +9,11 @@ DESCRIPTIONS = {
"Your attention is required at all times to use this feature."
),
"DisengageOnAccelerator": "When enabled, pressing the accelerator pedal will disengage openpilot.",
"LongitudinalPersonality": (
"Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " +
"In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with " +
"your steering wheel distance button."
),
"IsLdwEnabled": (
"Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line " +
"without a turn signal activated while driving over 31 mph (50 km/h)."
@@ -41,6 +46,15 @@ class TogglesLayout(Widget):
self._params.get_bool("DisengageOnAccelerator"),
icon="disengage_on_accelerator.png",
),
multiple_button_item(
"Driving Personality",
DESCRIPTIONS["LongitudinalPersonality"],
buttons=["Aggressive", "Standard", "Relaxed"],
button_width=255,
callback=self._set_longitudinal_personality,
selected_index=int(self._params.get("LongitudinalPersonality") or 0),
icon="speed_limit.png"
),
toggle_item(
"Enable Lane Departure Warnings",
DESCRIPTIONS["IsLdwEnabled"],
@@ -68,3 +82,6 @@ class TogglesLayout(Widget):
def _render(self, rect):
self._list_widget.render(rect)
def _set_longitudinal_personality(self, button_index: int):
self._params.put("LongitudinalPersonality", str(button_index))
+59
View File
@@ -149,6 +149,59 @@ class DualButtonAction(ItemAction):
return False
class MultipleButtonAction(ItemAction):
def __init__(self, buttons: list[str], button_width: int, selected_index: int = 0, callback: Callable = None):
super().__init__(width=len(buttons) * (button_width + 20), enabled=True)
self.buttons = buttons
self.button_width = button_width
self.selected_button = selected_index
self.callback = callback
self._font = gui_app.font(FontWeight.MEDIUM)
def _render(self, rect: rl.Rectangle) -> bool:
spacing = 20
button_y = rect.y + (rect.height - 100) / 2
clicked = -1
for i, text in enumerate(self.buttons):
button_x = rect.x + i * (self.button_width + spacing)
button_rect = rl.Rectangle(button_x, button_y, self.button_width, 100)
# Check button state
mouse_pos = rl.get_mouse_position()
is_hovered = rl.check_collision_point_rec(mouse_pos, button_rect)
is_pressed = is_hovered and rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT)
is_selected = i == self.selected_button
# Button colors
if is_selected:
bg_color = rl.Color(51, 171, 76, 255) # Green
elif is_pressed:
bg_color = rl.Color(74, 74, 74, 255) # Dark gray
else:
bg_color = rl.Color(57, 57, 57, 255) # Gray
# Draw button
rl.draw_rectangle_rounded(button_rect, 1.0, 20, bg_color)
# Draw text
text_size = measure_text_cached(self._font, text, 40)
text_x = button_x + (self.button_width - text_size.x) / 2
text_y = button_y + (100 - text_size.y) / 2
rl.draw_text_ex(self._font, text, rl.Vector2(text_x, text_y), 40, 0, rl.Color(228, 228, 228, 255))
# Handle click
if is_hovered and rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
clicked = i
if clicked >= 0:
self.selected_button = clicked
if self.callback:
self.callback(clicked)
return True
return False
@dataclass
class ListItem:
title: str
@@ -391,3 +444,9 @@ def dual_button_item(left_text: str, right_text: str, left_callback: Callable =
visible: bool | Callable[[], bool] = True) -> ListItem:
action = DualButtonAction(left_text, right_text, left_callback, right_callback, enabled)
return ListItem(title="", description=description, action_item=action, visible=visible)
def multiple_button_item(title: str, description: str, buttons: list[str], selected_index: int,
button_width: int = BUTTON_WIDTH, callback: Callable = None, icon: str = ""):
action = MultipleButtonAction(buttons, button_width, selected_index, callback=callback)
return ListItem(title=title, description=description, icon=icon, action_item=action)