mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-02-18 11:53:57 +08:00
[TIZI/TICI] ui: Cruise panel (#1691)
* init cruise panel * init descriptions * damn descriptions * init SLA sub layout * reorder * icbm it * callback for `Custom ACC Speed Increments` toggle to update dependent UI elements dynamically. * works * more init * more * [TIZI/TICI] ui: individual button states support for MultipleButtonActionSP * less * convert * init properly --------- Co-authored-by: nayan <nayan8teen@gmail.com>
This commit is contained in:
@@ -4,27 +4,190 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.ui.widgets.scroller_tici import Scroller
|
||||
from enum import IntEnum
|
||||
|
||||
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.cruise_sub_layouts.speed_limit_settings import SpeedLimitSettingsLayout
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.system.ui.lib.multilang import tr, tr_noop
|
||||
from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp, option_item_sp, simple_button_item_sp
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
from openpilot.system.ui.widgets.scroller_tici import Scroller
|
||||
|
||||
|
||||
class PanelType(IntEnum):
|
||||
CRUISE = 0
|
||||
SLA = 1
|
||||
|
||||
|
||||
ICBM_DESC = tr_noop("When enabled, sunnypilot will attempt to manage the built-in cruise control buttons " +
|
||||
"by emulating button presses for limited longitudinal control.")
|
||||
ICMB_UNAVAILABLE = tr_noop("Intelligent Cruise Button Management is currently unavailable on this platform.")
|
||||
ICMB_UNAVAILABLE_LONG_AVAILABLE = tr_noop("Disable the sunnypilot Longitudinal Control (alpha) toggle to allow Intelligent Cruise Button Management.")
|
||||
ICMB_UNAVAILABLE_LONG_UNAVAILABLE = tr_noop("sunnypilot Longitudinal Control is the default longitudinal control for this platform.")
|
||||
|
||||
ACC_ENABLED_DESCRIPTION = tr_noop("Enable custom Short & Long press increments for cruise speed increase/decrease.")
|
||||
ACC_NOLONG_DESCRIPTION = tr_noop("This feature can only be used with sunnypilot longitudinal control enabled.")
|
||||
ACC_PCMCRUISE_DISABLED_DESCRIPTION = tr_noop("This feature is not supported on this platform due to vehicle limitations.")
|
||||
ONROAD_ONLY_DESCRIPTION = tr_noop("Start the vehicle to check vehicle compatibility.")
|
||||
|
||||
|
||||
class CruiseLayout(Widget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._current_panel = PanelType.CRUISE
|
||||
self._speed_limit_layout = SpeedLimitSettingsLayout(lambda: self._set_current_panel(PanelType.CRUISE))
|
||||
|
||||
self._params = Params()
|
||||
items = self._initialize_items()
|
||||
self._scroller = Scroller(items, line_separator=True, spacing=0)
|
||||
|
||||
def _initialize_items(self):
|
||||
|
||||
self.icbm_toggle = toggle_item_sp(
|
||||
title=tr("Intelligent Cruise Button Management (ICBM) (Alpha)"),
|
||||
description="",
|
||||
param="IntelligentCruiseButtonManagement")
|
||||
|
||||
self.scc_v_toggle = toggle_item_sp(
|
||||
title=tr("Smart Cruise Control - Vision"),
|
||||
description=tr("Use vision path predictions to estimate the appropriate speed to drive through turns ahead."),
|
||||
param="SmartCruiseControlVision")
|
||||
|
||||
self.scc_m_toggle = toggle_item_sp(
|
||||
title=tr("Smart Cruise Control - Map"),
|
||||
description=tr("Use map data to estimate the appropriate speed to drive through turns ahead."),
|
||||
param="SmartCruiseControlMap")
|
||||
|
||||
self.custom_acc_toggle = toggle_item_sp(
|
||||
title=tr("Custom ACC Speed Increments"),
|
||||
description="",
|
||||
param="CustomAccIncrementsEnabled",
|
||||
callback=self._on_custom_acc_toggle)
|
||||
|
||||
self.custom_acc_short_increment = option_item_sp(
|
||||
title=tr("Short Press Increment"),
|
||||
param="CustomAccShortPressIncrement",
|
||||
min_value=1, max_value=10, value_change_step=1,
|
||||
inline=True)
|
||||
|
||||
self.custom_acc_long_increment = option_item_sp(
|
||||
title=tr("Long Press Increment"),
|
||||
param="CustomAccLongPressIncrement",
|
||||
value_map={1: 1, 2: 5, 3: 10},
|
||||
min_value=1, max_value=3, value_change_step=1,
|
||||
inline=True)
|
||||
|
||||
self.sla_settings_button = simple_button_item_sp(
|
||||
button_text=lambda: tr("Speed Limit"),
|
||||
button_width=800,
|
||||
callback=lambda: self._set_current_panel(PanelType.SLA)
|
||||
)
|
||||
|
||||
self.dec_toggle = toggle_item_sp(
|
||||
title=tr("Enable Dynamic Experimental Control"),
|
||||
description=tr("Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal."),
|
||||
param="DynamicExperimentalControl")
|
||||
|
||||
items = [
|
||||
self.icbm_toggle,
|
||||
self.dec_toggle,
|
||||
self.scc_v_toggle,
|
||||
self.scc_m_toggle,
|
||||
self.custom_acc_toggle,
|
||||
self.custom_acc_short_increment,
|
||||
self.custom_acc_long_increment,
|
||||
self.sla_settings_button,
|
||||
]
|
||||
return items
|
||||
|
||||
def _render(self, rect):
|
||||
self._scroller.render(rect)
|
||||
if self._current_panel == PanelType.SLA:
|
||||
self._speed_limit_layout.render(rect)
|
||||
else:
|
||||
self._scroller.render(rect)
|
||||
|
||||
def show_event(self):
|
||||
self._set_current_panel(PanelType.CRUISE)
|
||||
self._scroller.show_event()
|
||||
self.icbm_toggle.show_description(True)
|
||||
self.custom_acc_toggle.show_description(True)
|
||||
|
||||
def _set_current_panel(self, panel: PanelType):
|
||||
self._current_panel = panel
|
||||
if panel == PanelType.SLA:
|
||||
self._speed_limit_layout.show_event()
|
||||
|
||||
def _update_state(self):
|
||||
super()._update_state()
|
||||
|
||||
if ui_state.CP is not None and ui_state.CP_SP is not None:
|
||||
has_icbm = ui_state.has_icbm
|
||||
has_long = ui_state.has_longitudinal_control
|
||||
|
||||
if ui_state.CP_SP.intelligentCruiseButtonManagementAvailable and not has_long:
|
||||
self.icbm_toggle.action_item.set_enabled(ui_state.is_offroad())
|
||||
self.icbm_toggle.set_description(tr(ICBM_DESC))
|
||||
else:
|
||||
ui_state.params.remove("IntelligentCruiseButtonManagement")
|
||||
self.icbm_toggle.action_item.set_enabled(False)
|
||||
|
||||
long_desc = ICMB_UNAVAILABLE
|
||||
if has_long:
|
||||
if ui_state.CP.alphaLongitudinalAvailable:
|
||||
long_desc += " " + ICMB_UNAVAILABLE_LONG_AVAILABLE
|
||||
else:
|
||||
long_desc += " " + ICMB_UNAVAILABLE_LONG_UNAVAILABLE
|
||||
|
||||
new_desc = "<b>" + tr(long_desc) + "</b>\n\n" + tr(ICBM_DESC)
|
||||
if self.icbm_toggle.description != new_desc:
|
||||
self.icbm_toggle.set_description(new_desc)
|
||||
self.icbm_toggle.show_description(True)
|
||||
|
||||
if has_long or has_icbm:
|
||||
self.custom_acc_toggle.action_item.set_enabled(((has_long and not ui_state.CP.pcmCruise) or has_icbm) and ui_state.is_offroad())
|
||||
self.dec_toggle.action_item.set_enabled(has_long)
|
||||
self.scc_v_toggle.action_item.set_enabled(True)
|
||||
self.scc_m_toggle.action_item.set_enabled(True)
|
||||
else:
|
||||
ui_state.params.remove("CustomAccIncrementsEnabled")
|
||||
ui_state.params.remove("DynamicExperimentalControl")
|
||||
ui_state.params.remove("SmartCruiseControlVision")
|
||||
ui_state.params.remove("SmartCruiseControlMap")
|
||||
self.custom_acc_toggle.action_item.set_enabled(False)
|
||||
self.dec_toggle.action_item.set_enabled(False)
|
||||
self.scc_v_toggle.action_item.set_enabled(False)
|
||||
self.scc_m_toggle.action_item.set_enabled(False)
|
||||
|
||||
else:
|
||||
has_icbm = has_long = False
|
||||
self.icbm_toggle.action_item.set_enabled(False)
|
||||
self.icbm_toggle.set_description(tr(ONROAD_ONLY_DESCRIPTION))
|
||||
|
||||
show_custom_acc_desc = False
|
||||
|
||||
if ui_state.is_offroad():
|
||||
new_custom_acc_desc = tr(ONROAD_ONLY_DESCRIPTION)
|
||||
show_custom_acc_desc = True
|
||||
else:
|
||||
if has_long or has_icbm:
|
||||
if has_long and ui_state.CP.pcmCruise:
|
||||
new_custom_acc_desc = tr(ACC_PCMCRUISE_DISABLED_DESCRIPTION)
|
||||
show_custom_acc_desc = True
|
||||
else:
|
||||
new_custom_acc_desc = tr(ACC_ENABLED_DESCRIPTION)
|
||||
else:
|
||||
new_custom_acc_desc = tr(ACC_NOLONG_DESCRIPTION)
|
||||
show_custom_acc_desc = True
|
||||
self.custom_acc_toggle.action_item.set_state(False)
|
||||
|
||||
if self.custom_acc_toggle.description != new_custom_acc_desc:
|
||||
self.custom_acc_toggle.set_description(new_custom_acc_desc)
|
||||
if show_custom_acc_desc:
|
||||
self.custom_acc_toggle.show_description(True)
|
||||
|
||||
self._on_custom_acc_toggle(self.custom_acc_toggle.action_item.get_state())
|
||||
|
||||
def _on_custom_acc_toggle(self, state):
|
||||
self.custom_acc_short_increment.set_visible(state)
|
||||
self.custom_acc_long_increment.set_visible(state)
|
||||
self.custom_acc_short_increment.action_item.set_enabled(self.custom_acc_toggle.action_item.enabled)
|
||||
self.custom_acc_long_increment.action_item.set_enabled(self.custom_acc_toggle.action_item.enabled)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from collections.abc import Callable
|
||||
|
||||
import pyray as rl
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.system.ui.lib.multilang import tr
|
||||
from openpilot.system.ui.sunnypilot.widgets.list_view import multiple_button_item_sp
|
||||
from openpilot.system.ui.widgets.network import NavButton
|
||||
from openpilot.system.ui.widgets.scroller_tici import Scroller
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
from openpilot.system.ui.sunnypilot.widgets import get_highlighted_description
|
||||
|
||||
SPEED_LIMIT_POLICY_BUTTONS = [tr("Car Only"), tr("Map Only"), tr("Car First"), tr("Map First"), tr("Combined")]
|
||||
|
||||
SPEED_LIMIT_POLICY_DESCRIPTIONS = [
|
||||
tr("Car Only: Use Speed Limit data only from Car"),
|
||||
tr("Map Only: Use Speed Limit data only from OpenStreetMaps"),
|
||||
tr("Car First: Use Speed Limit data from Car if available, else use from OpenStreetMaps"),
|
||||
tr("Map First: Use Speed Limit data from OpenStreetMaps if available, else use from Car"),
|
||||
tr("Combined: Use combined Speed Limit data from Car & OpenStreetMaps")
|
||||
]
|
||||
|
||||
|
||||
class SpeedLimitPolicyLayout(Widget):
|
||||
def __init__(self, back_btn_callback: Callable):
|
||||
super().__init__()
|
||||
self._back_button = NavButton(tr("Back"))
|
||||
self._back_button.set_click_callback(back_btn_callback)
|
||||
|
||||
items = self._initialize_items()
|
||||
self._scroller = Scroller(items, line_separator=False, spacing=0)
|
||||
|
||||
def _initialize_items(self):
|
||||
self._speed_limit_policy = multiple_button_item_sp(
|
||||
title=lambda: tr("Speed Limit Source"),
|
||||
description=self._get_policy_description,
|
||||
buttons=SPEED_LIMIT_POLICY_BUTTONS,
|
||||
param="SpeedLimitPolicy",
|
||||
button_width=250,
|
||||
)
|
||||
|
||||
items = [
|
||||
self._speed_limit_policy
|
||||
]
|
||||
return items
|
||||
|
||||
@staticmethod
|
||||
def _get_policy_description():
|
||||
return get_highlighted_description(ui_state.params, "SpeedLimitPolicy", SPEED_LIMIT_POLICY_DESCRIPTIONS)
|
||||
|
||||
def _render(self, rect):
|
||||
self._back_button.set_position(self._rect.x, self._rect.y + 20)
|
||||
self._back_button.render()
|
||||
|
||||
content_rect = rl.Rectangle(rect.x, rect.y + self._back_button.rect.height + 40, rect.width, rect.height - self._back_button.rect.height - 40)
|
||||
self._scroller.render(content_rect)
|
||||
|
||||
def show_event(self):
|
||||
self._scroller.show_event()
|
||||
self._speed_limit_policy.show_description(True)
|
||||
@@ -0,0 +1,178 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from collections.abc import Callable
|
||||
from enum import IntEnum
|
||||
|
||||
import pyray as rl
|
||||
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.cruise_sub_layouts.speed_limit_policy import SpeedLimitPolicyLayout
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode as SpeedLimitMode
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import OffsetType as SpeedLimitOffsetType
|
||||
from openpilot.system.ui.lib.multilang import tr
|
||||
from openpilot.system.ui.sunnypilot.widgets import get_highlighted_description
|
||||
from openpilot.system.ui.sunnypilot.widgets.list_view import multiple_button_item_sp, option_item_sp, simple_button_item_sp, LineSeparatorSP
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
from openpilot.system.ui.widgets.network import NavButton
|
||||
from openpilot.system.ui.widgets.scroller_tici import Scroller
|
||||
|
||||
SPEED_LIMIT_MODE_BUTTONS = [tr("Off"), tr("Info"), tr("Warning"), tr("Assist")]
|
||||
SPEED_LIMIT_OFFSET_TYPE_BUTTONS = [tr("None"), tr("Fixed"), tr("%")]
|
||||
|
||||
SPEED_LIMIT_MODE_DESCRIPTIONS = [
|
||||
tr("Off: Disables the Speed Limit functions."),
|
||||
tr("Information: Displays the current road's speed limit."),
|
||||
tr("Warning: Provides a warning when exceeding the current road's speed limit."),
|
||||
tr("Assist: Adjusts the vehicle's cruise speed based on the current road's speed limit when operating the +/- buttons."),
|
||||
]
|
||||
|
||||
SPEED_LIMIT_OFFSET_DESCRIPTIONS = [
|
||||
tr("None: No Offset"),
|
||||
tr("Fixed: Adds a fixed offset [Speed Limit + Offset]"),
|
||||
tr("Percent: Adds a percent offset [Speed Limit + (Offset % Speed Limit)]"),
|
||||
]
|
||||
|
||||
|
||||
class PanelType(IntEnum):
|
||||
SETTINGS = 0
|
||||
POLICY = 1
|
||||
|
||||
|
||||
class SpeedLimitSettingsLayout(Widget):
|
||||
def __init__(self, back_btn_callback: Callable):
|
||||
super().__init__()
|
||||
self._current_panel = PanelType.SETTINGS
|
||||
|
||||
self._back_button = NavButton(tr("Back"))
|
||||
self._back_button.set_click_callback(back_btn_callback)
|
||||
|
||||
self._policy_layout = SpeedLimitPolicyLayout(lambda: self._set_current_panel(PanelType.SETTINGS))
|
||||
|
||||
items = self._initialize_items()
|
||||
self._scroller = Scroller(items, line_separator=False, spacing=0)
|
||||
|
||||
def _initialize_items(self):
|
||||
self._speed_limit_mode = multiple_button_item_sp(
|
||||
title=lambda: tr("Speed Limit"),
|
||||
description=self._get_mode_description,
|
||||
buttons=SPEED_LIMIT_MODE_BUTTONS,
|
||||
param="SpeedLimitMode",
|
||||
button_width=380,
|
||||
)
|
||||
|
||||
self._source_button = simple_button_item_sp(
|
||||
button_text=lambda: tr("Customize Source"),
|
||||
button_width=720,
|
||||
callback=lambda: self._set_current_panel(PanelType.POLICY)
|
||||
)
|
||||
|
||||
self._speed_limit_offset_type = multiple_button_item_sp(
|
||||
title=lambda: tr("Speed Limit Offset"),
|
||||
description="",
|
||||
buttons=SPEED_LIMIT_OFFSET_TYPE_BUTTONS,
|
||||
param="SpeedLimitOffsetType",
|
||||
button_width=450,
|
||||
)
|
||||
|
||||
self._speed_limit_value_offset = option_item_sp(
|
||||
title="",
|
||||
param="SpeedLimitValueOffset",
|
||||
min_value=-30,
|
||||
max_value=30,
|
||||
description=self._get_offset_description,
|
||||
label_callback=self._get_offset_label,
|
||||
)
|
||||
|
||||
items = [
|
||||
self._speed_limit_mode,
|
||||
LineSeparatorSP(40),
|
||||
self._source_button,
|
||||
LineSeparatorSP(40),
|
||||
self._speed_limit_offset_type,
|
||||
self._speed_limit_value_offset
|
||||
]
|
||||
return items
|
||||
|
||||
def _set_current_panel(self, panel: PanelType):
|
||||
self._current_panel = panel
|
||||
if panel == PanelType.POLICY:
|
||||
self._policy_layout.show_event()
|
||||
|
||||
@staticmethod
|
||||
def _get_mode_description():
|
||||
return get_highlighted_description(ui_state.params, "SpeedLimitMode", SPEED_LIMIT_MODE_DESCRIPTIONS)
|
||||
|
||||
@staticmethod
|
||||
def _get_offset_description():
|
||||
return get_highlighted_description(ui_state.params, "SpeedLimitOffsetType", SPEED_LIMIT_OFFSET_DESCRIPTIONS)
|
||||
|
||||
@staticmethod
|
||||
def _get_offset_label(value):
|
||||
offset_type = int(ui_state.params.get("SpeedLimitOffsetType", return_default=True))
|
||||
unit = tr("km/h") if ui_state.is_metric else tr("mph")
|
||||
|
||||
if offset_type == int(SpeedLimitOffsetType.percentage):
|
||||
return f"{value}%"
|
||||
elif offset_type == int(SpeedLimitOffsetType.fixed):
|
||||
return f"{value} {unit}"
|
||||
return str(value)
|
||||
|
||||
def _update_state(self):
|
||||
super()._update_state()
|
||||
|
||||
speed_limit_mode_param = ui_state.params.get("SpeedLimitMode", return_default=True)
|
||||
if ui_state.CP is not None and ui_state.CP_SP is not None:
|
||||
brand = ui_state.CP.brand
|
||||
has_long = ui_state.has_longitudinal_control
|
||||
has_icbm = ui_state.has_icbm
|
||||
|
||||
"""
|
||||
Speed Limit Assist is available when:
|
||||
- has_long or has_icbm, and
|
||||
- is not a release branch or not a disallowed brand, and
|
||||
- is not always disallwed
|
||||
"""
|
||||
sla_disallow_in_release = brand == "tesla" and ui_state.is_sp_release
|
||||
sla_always_disallow = brand == "rivian"
|
||||
sla_available = (has_long or has_icbm) and not sla_disallow_in_release and not sla_always_disallow
|
||||
|
||||
if not sla_available and speed_limit_mode_param == int(SpeedLimitMode.assist):
|
||||
ui_state.params.put("SpeedLimitMode", int(SpeedLimitMode.warning))
|
||||
|
||||
else:
|
||||
sla_available = False
|
||||
|
||||
if not sla_available:
|
||||
self._speed_limit_mode.action_item.set_enabled_buttons({
|
||||
int(SpeedLimitMode.off),
|
||||
int(SpeedLimitMode.information),
|
||||
int(SpeedLimitMode.warning),
|
||||
})
|
||||
else:
|
||||
self._speed_limit_mode.action_item.set_enabled_buttons(None)
|
||||
|
||||
offset_type = ui_state.params.get("SpeedLimitOffsetType", return_default=True)
|
||||
self._speed_limit_value_offset.set_visible(offset_type != int(SpeedLimitOffsetType.off))
|
||||
|
||||
def _render(self, rect):
|
||||
if self._current_panel == PanelType.POLICY:
|
||||
self._policy_layout.render(rect)
|
||||
return
|
||||
|
||||
self._back_button.set_position(self._rect.x, self._rect.y + 20)
|
||||
self._back_button.render()
|
||||
|
||||
content_rect = rl.Rectangle(rect.x, rect.y + self._back_button.rect.height + 40, rect.width, rect.height - self._back_button.rect.height - 40)
|
||||
self._scroller.render(content_rect)
|
||||
|
||||
def show_event(self):
|
||||
self._current_panel = PanelType.SETTINGS
|
||||
self._scroller.show_event()
|
||||
self._speed_limit_mode.show_description(True)
|
||||
|
||||
def hide_event(self):
|
||||
self._current_panel = PanelType.SETTINGS
|
||||
self._scroller.hide_event()
|
||||
@@ -39,6 +39,9 @@ class UIStateSP:
|
||||
self.onroad_brightness_timer: int = 0
|
||||
self.custom_interactive_timeout: int = self.params.get("InteractivityTimeout", return_default=True)
|
||||
self.reset_onroad_sleep_timer()
|
||||
self.CP_SP: custom.CarParamsSP | None = None
|
||||
self.has_icbm: bool = False
|
||||
self.is_sp_release: bool = self.params.get_bool("IsReleaseSpBranch")
|
||||
|
||||
def update(self) -> None:
|
||||
if self.sunnylink_enabled:
|
||||
@@ -121,6 +124,7 @@ class UIStateSP:
|
||||
CP_SP_bytes = self.params.get("CarParamsSPPersistent")
|
||||
if CP_SP_bytes is not None:
|
||||
self.CP_SP = messaging.log_from_bytes(CP_SP_bytes, custom.CarParamsSP)
|
||||
self.has_icbm = self.CP_SP.intelligentCruiseButtonManagementAvailable and self.params.get_bool("IntelligentCruiseButtonManagement")
|
||||
self.active_bundle = self.params.get("ModelManager_ActiveBundle")
|
||||
self.blindspot = self.params.get_bool("BlindSpot")
|
||||
self.chevron_metrics = self.params.get("ChevronInfo")
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
|
||||
def get_highlighted_description(params, param_name: str, descriptions: list[str]) -> str:
|
||||
index = int(params.get(param_name, return_default=True))
|
||||
lines = []
|
||||
for i, desc in enumerate(descriptions):
|
||||
if i == index:
|
||||
lines.append(f"<b>{desc}</b>")
|
||||
else:
|
||||
lines.append(f"{desc}")
|
||||
|
||||
return "<br>".join(lines)
|
||||
|
||||
Reference in New Issue
Block a user