mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-15 22:32:11 +08:00
Big UI: Quick Vehicle Panel Cleanup WIP
This commit is contained in:
@@ -7,9 +7,10 @@ from dataclasses import replace
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
from openpilot.system.ui.lib.multilang import tr, tr_noop
|
||||
from openpilot.system.ui.widgets import DialogResult
|
||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||
from openpilot.system.ui.widgets import DialogResult, Widget
|
||||
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog, alert_dialog
|
||||
from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import _SettingsPage
|
||||
@@ -28,7 +29,11 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
GROUP_HEADER_LINE_GAP,
|
||||
draw_group_header,
|
||||
draw_list_group_shell,
|
||||
draw_rounded_fill,
|
||||
draw_rounded_stroke,
|
||||
draw_settings_list_row,
|
||||
draw_soft_card,
|
||||
mix_colors,
|
||||
)
|
||||
from openpilot.selfdrive.ui.lib.starpilot_state import starpilot_state
|
||||
from openpilot.selfdrive.ui.lib.fingerprint_catalog import (
|
||||
@@ -128,28 +133,41 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
def _build_steering_rows(self) -> list[SettingRow]:
|
||||
cs = starpilot_state.car_state
|
||||
rows = []
|
||||
for key in ("DistanceButtonControl", "LongDistanceButtonControl", "VeryLongDistanceButtonControl"):
|
||||
rows.append(SettingRow(key, "value", tr_noop(self._controller._action_title(key)),
|
||||
get_value=lambda k=key: self._controller._get_action_name(k),
|
||||
on_click=lambda k=key: self._controller._on_select(k)))
|
||||
|
||||
rows.append(SettingRow(
|
||||
"combo:distance", "value", tr_noop("Distance Button"),
|
||||
get_value=lambda: self._controller._get_action_name("DistanceButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("combo:distance"),
|
||||
))
|
||||
|
||||
if cs.isBolt and cs.hasPedal and self._controller._params.get_bool("RemapCancelToDistance"):
|
||||
for key in ("CancelButtonControl", "LongCancelButtonControl", "VeryLongCancelButtonControl"):
|
||||
rows.append(SettingRow(key, "value", tr_noop(self._controller._action_title(key)),
|
||||
get_value=lambda k=key: self._controller._get_action_name(k),
|
||||
on_click=lambda k=key: self._controller._on_select(k)))
|
||||
rows.append(SettingRow(
|
||||
"combo:cancel", "value", tr_noop("Cancel Button"),
|
||||
get_value=lambda: self._controller._get_action_name("CancelButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("combo:cancel"),
|
||||
))
|
||||
|
||||
if not cs.isSubaru:
|
||||
rows.append(SettingRow("LKASButtonControl", "value", tr_noop("LKAS Button"),
|
||||
get_value=lambda: self._controller._get_action_name("LKASButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("LKASButtonControl")))
|
||||
get_value=lambda: self._controller._get_action_name("LKASButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("LKASButtonControl")))
|
||||
|
||||
rows.append(SettingRow("MainCruiseButtonControl", "value", tr_noop("CC Main Button"),
|
||||
get_value=lambda: self._controller._get_action_name("MainCruiseButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("MainCruiseButtonControl")))
|
||||
|
||||
if cs.hasModeStarButtons:
|
||||
for key in ("ModeButtonControl", "LongModeButtonControl", "VeryLongModeButtonControl",
|
||||
"StarButtonControl", "LongStarButtonControl", "VeryLongStarButtonControl"):
|
||||
rows.append(SettingRow(key, "value", tr_noop(self._controller._action_title(key)),
|
||||
get_value=lambda k=key: self._controller._get_action_name(k),
|
||||
on_click=lambda k=key: self._controller._on_select(k)))
|
||||
rows.append(SettingRow(
|
||||
"combo:mode", "value", tr_noop("Mode Button"),
|
||||
get_value=lambda: self._controller._get_action_name("ModeButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("combo:mode"),
|
||||
))
|
||||
rows.append(SettingRow(
|
||||
"combo:star", "value", tr_noop("Star Button"),
|
||||
get_value=lambda: self._controller._get_action_name("StarButtonControl"),
|
||||
on_click=lambda: self._controller._on_select("combo:star"),
|
||||
))
|
||||
|
||||
return rows
|
||||
|
||||
def _draw_row(self, rect: rl.Rectangle, row: SettingRow, is_last: bool):
|
||||
@@ -158,13 +176,21 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
enabled = row.enabled() if row.enabled is not None else True
|
||||
subtitle = row.disabled_label if not enabled and row.disabled_label else (tr(row.subtitle) if row.subtitle else "")
|
||||
|
||||
row_h = rect.height
|
||||
if row_h < 100:
|
||||
title_size = max(26, int(49 * row_h / 100))
|
||||
subtitle = ""
|
||||
else:
|
||||
title_size = 49
|
||||
|
||||
if row.type == "value":
|
||||
value_size = max(24, int(44 * row_h / 100)) if row_h < 100 else 44
|
||||
value_text = row.get_value() if row.get_value else ""
|
||||
draw_settings_list_row(rect, title=tr(row.title), subtitle=subtitle,
|
||||
value=value_text, enabled=enabled,
|
||||
hovered=hovered, pressed=pressed,
|
||||
is_last=is_last, show_chevron=row.on_click is not None,
|
||||
title_size=49, subtitle_size=38, value_size=44,
|
||||
title_size=title_size, subtitle_size=38, value_size=value_size,
|
||||
style=PANEL_STYLE)
|
||||
elif row.type == "toggle":
|
||||
toggle_value = row.get_state() if row.get_state else False
|
||||
@@ -172,7 +198,7 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
toggle_value=toggle_value, enabled=enabled,
|
||||
hovered=hovered, pressed=pressed,
|
||||
is_last=is_last, show_chevron=False,
|
||||
title_size=49, subtitle_size=38,
|
||||
title_size=title_size, 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:
|
||||
@@ -416,6 +442,137 @@ class VehicleSettingsManagerView(PanelManagerView):
|
||||
self._controller._on_select(value)
|
||||
|
||||
|
||||
class ButtonActionComboDialog(Widget):
|
||||
_DIALOG_W = 660
|
||||
_DIALOG_H = 440
|
||||
|
||||
def __init__(self, controller: "StarPilotVehicleSettingsLayout", title: str,
|
||||
keys: tuple[str, ...], labels: tuple[str, ...]):
|
||||
super().__init__()
|
||||
self._controller = controller
|
||||
self._title = title
|
||||
self._keys = keys
|
||||
self._labels = labels
|
||||
self._pressed_idx: int | None = None
|
||||
self._pressed_close = False
|
||||
self._font_title = gui_app.font(FontWeight.BOLD)
|
||||
self._font_btn = gui_app.font(FontWeight.SEMI_BOLD)
|
||||
|
||||
def _layout(self):
|
||||
sw = gui_app.width
|
||||
sh = gui_app.height
|
||||
dx = (sw - self._DIALOG_W) / 2
|
||||
dy = (sh - self._DIALOG_H) / 2
|
||||
d_rect = rl.Rectangle(int(dx), int(dy), int(self._DIALOG_W), int(self._DIALOG_H))
|
||||
|
||||
rows_area_y = dy + 72
|
||||
rows_area_h = len(self._keys) * 88 + 12
|
||||
rows_area = rl.Rectangle(int(dx + 40), int(rows_area_y), int(self._DIALOG_W - 80), int(rows_area_h))
|
||||
|
||||
row_rects = []
|
||||
for i in range(len(self._keys)):
|
||||
row_rects.append(rl.Rectangle(
|
||||
int(dx + 40), int(rows_area_y + i * 88),
|
||||
int(self._DIALOG_W - 80), 88,
|
||||
))
|
||||
|
||||
close_w = 320
|
||||
close_h = 64
|
||||
close_rect = rl.Rectangle(
|
||||
int(dx + (self._DIALOG_W - close_w) / 2),
|
||||
int(dy + self._DIALOG_H - 36 - close_h),
|
||||
close_w, close_h,
|
||||
)
|
||||
return d_rect, rows_area, row_rects, close_rect
|
||||
|
||||
def _handle_mouse_press(self, mouse_pos):
|
||||
_, _, row_rects, close_rect = self._layout()
|
||||
if rl.check_collision_point_rec(mouse_pos, close_rect):
|
||||
self._pressed_close = True
|
||||
return
|
||||
for i, rect in enumerate(row_rects):
|
||||
if rl.check_collision_point_rec(mouse_pos, rect):
|
||||
self._pressed_idx = i
|
||||
return
|
||||
|
||||
def _handle_mouse_release(self, mouse_pos):
|
||||
if self._pressed_idx is not None:
|
||||
idx = self._pressed_idx
|
||||
self._pressed_idx = None
|
||||
_, _, row_rects, _ = self._layout()
|
||||
if idx < len(row_rects) and rl.check_collision_point_rec(mouse_pos, row_rects[idx]):
|
||||
self._controller._show_action_picker(self._keys[idx])
|
||||
return
|
||||
if self._pressed_close:
|
||||
self._pressed_close = False
|
||||
_, _, _, close_rect = self._layout()
|
||||
if rl.check_collision_point_rec(mouse_pos, close_rect):
|
||||
gui_app.pop_widget()
|
||||
|
||||
def _render(self, rect):
|
||||
sw = gui_app.width
|
||||
sh = gui_app.height
|
||||
rl.draw_rectangle(0, 0, sw, sh, rl.Color(0, 0, 0, 160))
|
||||
|
||||
d_rect, rows_area, row_rects, close_rect = self._layout()
|
||||
mouse_pos = gui_app.last_mouse_event.pos
|
||||
|
||||
draw_rounded_fill(d_rect, rl.Color(10, 12, 16, 255), radius_px=24)
|
||||
draw_rounded_stroke(d_rect, rl.Color(255, 255, 255, 16), radius_px=24)
|
||||
rl.draw_rectangle_rec(rl.Rectangle(d_rect.x, d_rect.y, d_rect.width, 4), PANEL_STYLE.accent)
|
||||
|
||||
title_size = 32
|
||||
ts = measure_text_cached(self._font_title, self._title, title_size)
|
||||
rl.draw_text_ex(self._font_title, self._title,
|
||||
rl.Vector2(int(d_rect.x + (d_rect.width - ts.x) / 2),
|
||||
int(d_rect.y + (64 - title_size) / 2)),
|
||||
title_size, 0, rl.WHITE)
|
||||
|
||||
draw_list_group_shell(rows_area, style=PANEL_STYLE)
|
||||
|
||||
for i in range(len(self._keys)):
|
||||
row_rect = row_rects[i]
|
||||
hovered = rl.check_collision_point_rec(mouse_pos, row_rect)
|
||||
pressed = self._pressed_idx == i
|
||||
|
||||
draw_settings_list_row(
|
||||
row_rect,
|
||||
title=self._labels[i],
|
||||
value=self._controller._get_action_name(self._keys[i]),
|
||||
enabled=True,
|
||||
hovered=hovered and (self._pressed_idx is None),
|
||||
pressed=pressed,
|
||||
is_last=(i == len(self._keys) - 1),
|
||||
show_chevron=True,
|
||||
title_size=46,
|
||||
value_size=42,
|
||||
style=PANEL_STYLE,
|
||||
)
|
||||
|
||||
close_hovered = rl.check_collision_point_rec(mouse_pos, close_rect)
|
||||
close_pressed = self._pressed_close
|
||||
|
||||
if close_pressed:
|
||||
close_fill = mix_colors(PANEL_STYLE.accent, rl.Color(0, 0, 0, 255), 0.2)
|
||||
close_border = PANEL_STYLE.accent
|
||||
elif close_hovered:
|
||||
close_fill = PANEL_STYLE.accent
|
||||
close_border = PANEL_STYLE.accent
|
||||
else:
|
||||
close_fill = rl.Color(255, 255, 255, 14)
|
||||
close_border = rl.Color(255, 255, 255, 28)
|
||||
|
||||
draw_soft_card(close_rect, close_fill, close_border)
|
||||
|
||||
close_text = tr("Close")
|
||||
close_size = 22
|
||||
cts = measure_text_cached(self._font_btn, close_text, close_size)
|
||||
rl.draw_text_ex(self._font_btn, close_text,
|
||||
rl.Vector2(int(close_rect.x + (close_rect.width - cts.x) / 2),
|
||||
int(close_rect.y + (close_rect.height - cts.y) / 2)),
|
||||
close_size, 0, rl.WHITE)
|
||||
|
||||
|
||||
class StarPilotVehicleSettingsLayout(_SettingsPage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -498,6 +655,9 @@ class StarPilotVehicleSettingsLayout(_SettingsPage):
|
||||
gui_app.push_widget(ConfirmDialog(prompt, tr("Flash"), callback=on_confirm))
|
||||
|
||||
def _on_select(self, key: str):
|
||||
if key.startswith("combo:"):
|
||||
self._show_button_combo_dialog(key)
|
||||
return
|
||||
if key in ("CarMake", "CarModel") and not self._params.get_bool("ForceFingerprint"):
|
||||
return
|
||||
if key == "CarMake":
|
||||
@@ -511,6 +671,37 @@ class StarPilotVehicleSettingsLayout(_SettingsPage):
|
||||
else:
|
||||
self._show_action_picker(key)
|
||||
|
||||
def _show_button_combo_dialog(self, key: str):
|
||||
combo_configs = {
|
||||
"combo:distance": {
|
||||
"title": tr_noop("Distance Button"),
|
||||
"keys": ("DistanceButtonControl", "LongDistanceButtonControl", "VeryLongDistanceButtonControl"),
|
||||
"labels": (tr_noop("Press"), tr_noop("Long Press"), tr_noop("Very Long")),
|
||||
},
|
||||
"combo:cancel": {
|
||||
"title": tr_noop("Cancel Button"),
|
||||
"keys": ("CancelButtonControl", "LongCancelButtonControl", "VeryLongCancelButtonControl"),
|
||||
"labels": (tr_noop("Press"), tr_noop("Long Press"), tr_noop("Very Long")),
|
||||
},
|
||||
"combo:mode": {
|
||||
"title": tr_noop("Mode Button"),
|
||||
"keys": ("ModeButtonControl", "LongModeButtonControl", "VeryLongModeButtonControl"),
|
||||
"labels": (tr_noop("Press"), tr_noop("Long Press"), tr_noop("Very Long")),
|
||||
},
|
||||
"combo:star": {
|
||||
"title": tr_noop("Star Button"),
|
||||
"keys": ("StarButtonControl", "LongStarButtonControl", "VeryLongStarButtonControl"),
|
||||
"labels": (tr_noop("Press"), tr_noop("Long Press"), tr_noop("Very Long")),
|
||||
},
|
||||
}
|
||||
config = combo_configs.get(key)
|
||||
if config is None:
|
||||
return
|
||||
gui_app.push_widget(ButtonActionComboDialog(
|
||||
self, tr(config["title"]), config["keys"],
|
||||
tuple(tr(l) for l in config["labels"]),
|
||||
))
|
||||
|
||||
def _on_select_make(self):
|
||||
makes = list(self._make_options)
|
||||
if not makes:
|
||||
|
||||
Reference in New Issue
Block a user