mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-06-30 19:12:07 +08:00
BigUI WIP: Start of lateral
This commit is contained in:
@@ -1,28 +1,45 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.selfdrive.ui.lib.starpilot_state import starpilot_state
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.lib.multilang import tr, tr_noop
|
||||
from openpilot.system.ui.widgets import DialogResult
|
||||
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanel, create_master_toggle_panel, create_tile_panel
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.tabbed_panel import TabSectionSpec, TabbedSectionHost
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import AetherSliderDialog
|
||||
|
||||
class StarPilotAdvancedLateralLayout(StarPilotPanel):
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import _SettingsPage
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.longitudinal import (
|
||||
SettingRow, SettingSection, AetherSettingsView,
|
||||
)
|
||||
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import (
|
||||
AETHER_LIST_METRICS,
|
||||
AetherSliderDialog,
|
||||
DEFAULT_PANEL_STYLE,
|
||||
)
|
||||
|
||||
|
||||
PANEL_STYLE = DEFAULT_PANEL_STYLE
|
||||
UTILITY_ROW_HEIGHT = AETHER_LIST_METRICS.utility_row_height
|
||||
|
||||
|
||||
def _confirm_reboot_toggle(params, key, state):
|
||||
params.put_bool(key, state)
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
if ui_state.started:
|
||||
gui_app.push_widget(ConfirmDialog(
|
||||
tr("Reboot required. Reboot now?"), tr("Reboot"), tr("Cancel"),
|
||||
callback=lambda res: HARDWARE.reboot() if res == DialogResult.CONFIRM else None,
|
||||
))
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# StarPilotAdvancedLateralLayout
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class StarPilotAdvancedLateralLayout(_SettingsPage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.CATEGORIES = [
|
||||
{"title": tr_noop("Actuator Delay"), "desc": tr_noop("The time between openpilot's steering command and the vehicle's response."), "type": "value", "get_value": lambda: f"{self._params.get_float('SteerDelay'):.2f}s", "on_click": lambda: self._show_float_selector("SteerDelay", 0.01, 1.0, 0.01, "s"), "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_steer_delay},
|
||||
{"title": tr_noop("Friction"), "desc": tr_noop("Compensates for steering friction around center."), "type": "value", "get_value": lambda: f"{self._params.get_float('SteerFriction'):.3f}", "on_click": self._show_steer_friction_selector, "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_steer_friction},
|
||||
{"title": tr_noop("Kp Factor"), "desc": tr_noop("How strongly openpilot corrects lateral position."), "type": "value", "get_value": lambda: f"{self._params.get_float('SteerKP'):.2f}", "on_click": self._show_steer_kp_selector, "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_steer_kp},
|
||||
{"title": tr_noop("Lateral Acceleration"), "desc": tr_noop("Maps steering torque to turning response."), "type": "value", "get_value": lambda: f"{self._params.get_float('SteerLatAccel'):.2f}", "on_click": self._show_steer_lat_accel_selector, "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_steer_lat_accel},
|
||||
{"title": tr_noop("Steer Ratio"), "desc": tr_noop("Adjust the relationship between steering wheel input and road-wheel angle."), "type": "value", "get_value": lambda: f"{self._params.get_float('SteerRatio'):.2f}", "on_click": self._show_steer_ratio_selector, "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_steer_ratio},
|
||||
{"title": tr_noop("Force Auto-Tune On"), "desc": tr_noop("Force-enable live auto-tuning for friction and lateral acceleration."), "type": "toggle", "get_state": lambda: self._params.get_bool("ForceAutoTune"), "set_state": self._set_force_auto_tune, "icon": "toggle_icons/icon_tuning.png", "color": "#597497", "visible": self._show_force_auto_tune},
|
||||
{"title": tr_noop("Force Auto-Tune Off"), "desc": tr_noop("Force-disable live auto-tuning and use your set values instead."), "type": "toggle", "get_state": lambda: self._params.get_bool("ForceAutoTuneOff"), "set_state": self._set_force_auto_tune_off, "icon": "toggle_icons/icon_tuning.png", "color": "#597497", "visible": self._show_force_auto_tune_off},
|
||||
{"title": tr_noop("Force Torque Controller"), "desc": tr_noop("Use torque-based steering control instead of the stock steering mode when supported."), "type": "toggle", "get_state": lambda: self._params.get_bool("ForceTorqueController"), "set_state": lambda x: self._on_reboot_toggle("ForceTorqueController", x), "icon": "toggle_icons/icon_advanced_lateral_tune.png", "color": "#597497", "visible": self._show_force_torque_controller},
|
||||
]
|
||||
self._rebuild_grid()
|
||||
self._build_view()
|
||||
|
||||
def _advanced_enabled(self):
|
||||
return self._params.get_bool("AdvancedLateralTune")
|
||||
@@ -47,240 +64,198 @@ class StarPilotAdvancedLateralLayout(StarPilotPanel):
|
||||
return self._forcing_auto_tune_off()
|
||||
return not self._forcing_auto_tune()
|
||||
|
||||
def _show_steer_delay(self):
|
||||
return self._advanced_enabled() and starpilot_state.car_state.steerActuatorDelay != 0
|
||||
def _build_view(self):
|
||||
adv = self._advanced_enabled
|
||||
torque = self._torque_tuning_active
|
||||
manual = self._manual_tuning_values_enabled
|
||||
nnff = self._using_nnff
|
||||
|
||||
def _show_steer_friction(self):
|
||||
return (self._advanced_enabled() and starpilot_state.car_state.friction != 0 and self._torque_tuning_active()
|
||||
and not self._using_nnff() and self._manual_tuning_values_enabled())
|
||||
|
||||
def _show_steer_kp(self):
|
||||
return (self._advanced_enabled() and starpilot_state.car_state.steerKp != 0 and self._torque_tuning_active()
|
||||
and not starpilot_state.car_state.isAngleCar)
|
||||
|
||||
def _show_steer_lat_accel(self):
|
||||
return (self._advanced_enabled() and starpilot_state.car_state.latAccelFactor != 0 and self._torque_tuning_active()
|
||||
and not self._using_nnff() and self._manual_tuning_values_enabled())
|
||||
|
||||
def _show_steer_ratio(self):
|
||||
return self._advanced_enabled() and starpilot_state.car_state.steerRatio != 0 and self._manual_tuning_values_enabled()
|
||||
|
||||
def _show_force_auto_tune(self):
|
||||
return (self._advanced_enabled() and not starpilot_state.car_state.hasAutoTune and not starpilot_state.car_state.isAngleCar
|
||||
and self._torque_tuning_active())
|
||||
|
||||
def _show_force_auto_tune_off(self):
|
||||
return self._advanced_enabled() and starpilot_state.car_state.hasAutoTune and not starpilot_state.car_state.isAngleCar
|
||||
|
||||
def _show_force_torque_controller(self):
|
||||
return self._advanced_enabled() and not starpilot_state.car_state.isAngleCar and not starpilot_state.car_state.isTorqueCar
|
||||
|
||||
def _set_force_auto_tune(self, state):
|
||||
self._params.put_bool("ForceAutoTune", state)
|
||||
if state:
|
||||
self._params.put_bool("ForceAutoTuneOff", False)
|
||||
|
||||
def _set_force_auto_tune_off(self, state):
|
||||
self._params.put_bool("ForceAutoTuneOff", state)
|
||||
if state:
|
||||
self._params.put_bool("ForceAutoTune", False)
|
||||
|
||||
def _show_steer_friction_selector(self):
|
||||
self._show_float_selector("SteerFriction", 0.0, max(1.0, starpilot_state.car_state.friction * 1.5), 0.01)
|
||||
|
||||
def _show_steer_kp_selector(self):
|
||||
base = max(0.01, starpilot_state.car_state.steerKp)
|
||||
self._show_float_selector("SteerKP", base * 0.5, base * 1.5, 0.01)
|
||||
|
||||
def _show_steer_lat_accel_selector(self):
|
||||
base = max(0.01, starpilot_state.car_state.latAccelFactor)
|
||||
self._show_float_selector("SteerLatAccel", base * 0.5, base * 1.5, 0.01)
|
||||
|
||||
def _show_steer_ratio_selector(self):
|
||||
base = max(0.01, starpilot_state.car_state.steerRatio)
|
||||
self._show_float_selector("SteerRatio", base * 0.5, base * 1.5, 0.01)
|
||||
|
||||
def _show_float_selector(self, key, min_v, max_v, step, unit=""):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_float(key, float(val))
|
||||
self._rebuild_grid()
|
||||
gui_app.push_widget(AetherSliderDialog(tr(key), min_v, max_v, step, self._params.get_float(key), on_close, unit=unit, color="#597497"))
|
||||
|
||||
def _on_reboot_toggle(self, key, state):
|
||||
self._params.put_bool(key, state)
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
if ui_state.started:
|
||||
dialog = ConfirmDialog(tr("Reboot required. Reboot now?"), tr("Reboot"), tr("Cancel"), callback=lambda res: HARDWARE.reboot() if res == DialogResult.CONFIRM else None)
|
||||
gui_app.push_widget(dialog)
|
||||
|
||||
class StarPilotAlwaysOnLateralLayout(StarPilotPanel):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.CATEGORIES = [
|
||||
{"title": tr_noop("Always On Lateral"), "type": "toggle", "get_state": lambda: self._params.get_bool("AlwaysOnLateral"), "set_state": lambda x: self._on_reboot_toggle("AlwaysOnLateral", x), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497"},
|
||||
{"title": tr_noop("Enable With LKAS"), "type": "toggle", "get_state": lambda: self._params.get_bool("AlwaysOnLateralLKAS"), "set_state": lambda x: self._params.put_bool("AlwaysOnLateralLKAS", x), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497", "visible": lambda: self._params.get_bool("AlwaysOnLateral") and starpilot_state.car_state.lkasAllowedForAOL},
|
||||
{"title": tr_noop("Pause Below"), "type": "value", "get_value": lambda: f"{self._params.get_int('PauseAOLOnBrake')} mph", "on_click": lambda: self._show_speed_selector("PauseAOLOnBrake"), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497", "visible": lambda: self._params.get_bool("AlwaysOnLateral")},
|
||||
sections = [
|
||||
SettingSection(tr_noop("Steering Tuning"), [
|
||||
SettingRow("SteerDelay", "value", tr_noop("Actuator Delay"),
|
||||
subtitle=tr_noop("The time between openpilot's steering command and the vehicle's response."),
|
||||
get_value=lambda: f"{self._params.get_float('SteerDelay'):.2f}s",
|
||||
on_click=lambda: self._show_slider("SteerDelay", 0.01, 1.0, step=0.01, unit="s", value_type="float"),
|
||||
visible=lambda: adv() and starpilot_state.car_state.steerActuatorDelay != 0),
|
||||
SettingRow("SteerFriction", "value", tr_noop("Friction"),
|
||||
subtitle=tr_noop("Compensates for steering friction around center."),
|
||||
get_value=lambda: f"{self._params.get_float('SteerFriction'):.3f}",
|
||||
on_click=lambda: self._show_slider("SteerFriction", 0.0, max(1.0, starpilot_state.car_state.friction * 1.5), step=0.01, value_type="float"),
|
||||
visible=lambda: adv() and starpilot_state.car_state.friction != 0 and torque() and not nnff() and manual()),
|
||||
SettingRow("SteerKP", "value", tr_noop("Kp Factor"),
|
||||
subtitle=tr_noop("How strongly openpilot corrects lateral position."),
|
||||
get_value=lambda: f"{self._params.get_float('SteerKP'):.2f}",
|
||||
on_click=lambda: self._show_slider("SteerKP", max(0.01, starpilot_state.car_state.steerKp) * 0.5, max(0.01, starpilot_state.car_state.steerKp) * 1.5, step=0.01, value_type="float"),
|
||||
visible=lambda: adv() and starpilot_state.car_state.steerKp != 0 and torque() and not starpilot_state.car_state.isAngleCar),
|
||||
SettingRow("SteerLatAccel", "value", tr_noop("Lateral Acceleration"),
|
||||
subtitle=tr_noop("Maps steering torque to turning response."),
|
||||
get_value=lambda: f"{self._params.get_float('SteerLatAccel'):.2f}",
|
||||
on_click=lambda: self._show_slider("SteerLatAccel", max(0.01, starpilot_state.car_state.latAccelFactor) * 0.5, max(0.01, starpilot_state.car_state.latAccelFactor) * 1.5, step=0.01, value_type="float"),
|
||||
visible=lambda: adv() and starpilot_state.car_state.latAccelFactor != 0 and torque() and not nnff() and manual()),
|
||||
SettingRow("SteerRatio", "value", tr_noop("Steer Ratio"),
|
||||
subtitle=tr_noop("Adjust the relationship between steering wheel input and road-wheel angle."),
|
||||
get_value=lambda: f"{self._params.get_float('SteerRatio'):.2f}",
|
||||
on_click=lambda: self._show_slider("SteerRatio", max(0.01, starpilot_state.car_state.steerRatio) * 0.5, max(0.01, starpilot_state.car_state.steerRatio) * 1.5, step=0.01, value_type="float"),
|
||||
visible=lambda: adv() and starpilot_state.car_state.steerRatio != 0 and manual()),
|
||||
SettingRow("ForceAutoTune", "toggle", tr_noop("Force Auto-Tune On"),
|
||||
subtitle=tr_noop("Force-enable live auto-tuning for friction and lateral acceleration."),
|
||||
get_state=lambda: self._params.get_bool("ForceAutoTune"),
|
||||
set_state=lambda s: (self._params.put_bool("ForceAutoTune", s), s and self._params.put_bool("ForceAutoTuneOff", False)),
|
||||
visible=lambda: adv() and not starpilot_state.car_state.hasAutoTune and not starpilot_state.car_state.isAngleCar and torque()),
|
||||
SettingRow("ForceAutoTuneOff", "toggle", tr_noop("Force Auto-Tune Off"),
|
||||
subtitle=tr_noop("Force-disable live auto-tuning and use your set values instead."),
|
||||
get_state=lambda: self._params.get_bool("ForceAutoTuneOff"),
|
||||
set_state=lambda s: (self._params.put_bool("ForceAutoTuneOff", s), s and self._params.put_bool("ForceAutoTune", False)),
|
||||
visible=lambda: adv() and starpilot_state.car_state.hasAutoTune and not starpilot_state.car_state.isAngleCar),
|
||||
SettingRow("ForceTorqueController", "toggle", tr_noop("Force Torque Controller"),
|
||||
subtitle=tr_noop("Use torque-based steering control instead of the stock steering mode when supported."),
|
||||
get_state=lambda: self._params.get_bool("ForceTorqueController"),
|
||||
set_state=lambda s: _confirm_reboot_toggle(self._params, "ForceTorqueController", s),
|
||||
visible=lambda: adv() and not starpilot_state.car_state.isAngleCar and not starpilot_state.car_state.isTorqueCar),
|
||||
], row_height=UTILITY_ROW_HEIGHT),
|
||||
]
|
||||
self._rebuild_grid()
|
||||
self._manager_view = AetherSettingsView(
|
||||
self, sections,
|
||||
header_title=tr_noop("Advanced Lateral Tuning"),
|
||||
header_subtitle=tr_noop("Adjust steering response, torque controller behavior, and auto-tuning controls."),
|
||||
panel_style=PANEL_STYLE,
|
||||
)
|
||||
|
||||
def _show_speed_selector(self, key):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_int(key, int(val))
|
||||
self._rebuild_grid()
|
||||
gui_app.push_widget(AetherSliderDialog(tr(key), 0, 100, 1, self._params.get_int(key), on_close, unit=" mph", color="#597497"))
|
||||
|
||||
def _on_reboot_toggle(self, key, state):
|
||||
self._params.put_bool(key, state)
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
if ui_state.started:
|
||||
gui_app.push_widget(ConfirmDialog(tr("Reboot required. Reboot now?"), tr("Reboot"), tr("Cancel"), callback=lambda res: HARDWARE.reboot() if res == DialogResult.CONFIRM else None))
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
# StarPilotLateralLayout — top-level hub with 3 tabs
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
|
||||
class StarPilotLaneChangesLayout(StarPilotPanel):
|
||||
class StarPilotLateralLayout(_SettingsPage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.CATEGORIES = [
|
||||
{"title": tr_noop("Lane Changes"), "type": "toggle", "get_state": lambda: self._params.get_bool("LaneChanges"), "set_state": lambda s: self._params.put_bool("LaneChanges", s), "icon": "toggle_icons/icon_lane.png", "color": "#597497"},
|
||||
{"title": tr_noop("Automatic Lane Changes"), "type": "toggle", "get_state": lambda: self._params.get_bool("NudgelessLaneChange"), "set_state": lambda s: self._params.put_bool("NudgelessLaneChange", s), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges")},
|
||||
{"title": tr_noop("Lane Change Delay"), "type": "value", "get_value": lambda: f"{self._params.get_float('LaneChangeTime'):.1f}s", "on_click": lambda: self._show_float_selector("LaneChangeTime", 0.0, 5.0, 0.1, "s"), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges") and self._params.get_bool("NudgelessLaneChange")},
|
||||
{"title": tr_noop("Min Lane Change Speed"), "type": "value", "get_value": lambda: f"{self._params.get_int('MinimumLaneChangeSpeed')} mph", "on_click": lambda: self._show_speed_selector("MinimumLaneChangeSpeed"), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges")},
|
||||
{"title": tr_noop("Minimum Lane Width"), "type": "value", "get_value": lambda: f"{self._params.get_float('LaneDetectionWidth'):.1f} ft", "on_click": lambda: self._show_float_selector("LaneDetectionWidth", 0.0, 15.0, 0.1, " ft"), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges") and self._params.get_bool("NudgelessLaneChange")},
|
||||
{"title": tr_noop("One Lane Change Per Signal"), "type": "toggle", "get_state": lambda: self._params.get_bool("OneLaneChange"), "set_state": lambda s: self._params.put_bool("OneLaneChange", s), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges")},
|
||||
{"title": tr_noop("Lane Change Smoothing"), "desc": tr_noop("How smoothly openpilot commits to a lane change. 10 is stock; lower values produce a gentler, more gradual maneuver."), "type": "value", "get_value": lambda: f"{self._params.get_int('LaneChangeSmoothing')}", "on_click": lambda: self._show_pace_selector("LaneChangeSmoothing"), "icon": "toggle_icons/icon_lane.png", "color": "#597497", "visible": lambda: self._params.get_bool("LaneChanges")},
|
||||
]
|
||||
self._rebuild_grid()
|
||||
|
||||
def _show_speed_selector(self, key):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_int(key, int(val))
|
||||
self._rebuild_grid()
|
||||
gui_app.push_widget(AetherSliderDialog(tr(key), 0, 100, 1, self._params.get_int(key), on_close, unit=" mph", color="#597497"))
|
||||
|
||||
def _show_float_selector(self, key, min_v, max_v, step, unit=""):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_float(key, float(val))
|
||||
self._rebuild_grid()
|
||||
gui_app.push_widget(AetherSliderDialog(tr(key), min_v, max_v, step, self._params.get_float(key), on_close, unit=unit, color="#597497"))
|
||||
|
||||
def _show_pace_selector(self, key):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_int(key, int(val))
|
||||
self._rebuild_grid()
|
||||
current = self._params.get_int(key) if self._params.get_int(key) > 0 else 10
|
||||
gui_app.set_modal_overlay(AetherSliderDialog(tr(key), 1, 10, 1, current, on_close, color="#597497"))
|
||||
|
||||
class StarPilotLateralTuneLayout(StarPilotPanel):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.CATEGORIES = [
|
||||
{"title": tr_noop("Force Turn Desires Below Lane Change Speed"), "desc": tr_noop("Allow openpilot to follow turn intent below the minimum lane change speed when signaling."), "type": "toggle", "get_state": lambda: self._params.get_bool("TurnDesires"), "set_state": lambda x: self._params.put_bool("TurnDesires", x), "icon": "toggle_icons/icon_lateral_tune.png", "color": "#597497", "visible": self._lateral_enabled},
|
||||
{"title": tr_noop("Neural Network Feedforward (NNFF)"), "desc": tr_noop("Use the full neural-network feedforward steering controller when available."), "type": "toggle", "get_state": lambda: self._params.get_bool("NNFF"), "set_state": self._set_nnff, "icon": "toggle_icons/icon_lateral_tune.png", "color": "#597497", "visible": self._show_nnff},
|
||||
{"title": tr_noop("Neural Network Feedforward (NNFF) Lite"), "desc": tr_noop("Use the lightweight NNFF steering logic when the full model is off."), "type": "toggle", "get_state": lambda: self._params.get_bool("NNFFLite"), "set_state": lambda x: self._on_reboot_toggle("NNFFLite", x), "icon": "toggle_icons/icon_lateral_tune.png", "color": "#597497", "visible": self._show_nnff_lite},
|
||||
]
|
||||
self._rebuild_grid()
|
||||
|
||||
def _lateral_enabled(self):
|
||||
return self._params.get_bool("LateralTune")
|
||||
|
||||
def _show_nnff(self):
|
||||
return self._lateral_enabled() and starpilot_state.car_state.hasNNFFLog and not starpilot_state.car_state.isAngleCar
|
||||
|
||||
def _show_nnff_lite(self):
|
||||
return self._lateral_enabled() and not self._params.get_bool("NNFF") and not starpilot_state.car_state.isAngleCar
|
||||
|
||||
def _set_nnff(self, state):
|
||||
self._params.put_bool("NNFF", state)
|
||||
if state:
|
||||
self._params.put_bool("NNFFLite", False)
|
||||
|
||||
def _on_reboot_toggle(self, key, state):
|
||||
self._params.put_bool(key, state)
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
if ui_state.started:
|
||||
gui_app.push_widget(ConfirmDialog(tr("Reboot required. Reboot now?"), tr("Reboot"), tr("Cancel"), callback=lambda res: HARDWARE.reboot() if res == DialogResult.CONFIRM else None))
|
||||
|
||||
class StarPilotLateralQOLLayout(StarPilotPanel):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.CATEGORIES = [
|
||||
{"title": tr_noop("Quality of Life"), "type": "toggle", "get_state": lambda: self._params.get_bool("QOLLateral"), "set_state": lambda x: self._params.put_bool("QOLLateral", x), "icon": "toggle_icons/icon_quality_of_life.png", "color": "#597497"},
|
||||
{"title": tr_noop("Pause Steering Below"), "type": "value", "get_value": lambda: f"{self._params.get_int('PauseLateralSpeed')} mph", "on_click": lambda: self._show_speed_selector("PauseLateralSpeed"), "icon": "toggle_icons/icon_quality_of_life.png", "color": "#597497", "visible": lambda: self._params.get_bool("QOLLateral")}
|
||||
]
|
||||
self._rebuild_grid()
|
||||
|
||||
def _show_speed_selector(self, key):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_int(key, int(val))
|
||||
self._rebuild_grid()
|
||||
gui_app.push_widget(AetherSliderDialog(tr(key), 0, 100, 1, self._params.get_int(key), on_close, unit=" mph", color="#597497"))
|
||||
|
||||
class StarPilotLateralLayout(StarPilotPanel):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
steering_panel = create_tile_panel([
|
||||
{"title": tr_noop("Always On Lateral"), "panel": "always_on_lateral", "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497"},
|
||||
{"title": tr_noop("Quality of Life"), "panel": "qol", "icon": "toggle_icons/icon_quality_of_life.png", "color": "#597497"},
|
||||
], {
|
||||
"always_on_lateral": StarPilotAlwaysOnLateralLayout(),
|
||||
"qol": StarPilotLateralQOLLayout(),
|
||||
})
|
||||
tune_panel = create_master_toggle_panel([
|
||||
{
|
||||
"title": tr_noop("Advanced Lateral Tuning"),
|
||||
"desc": tr_noop("Advanced steering control changes to fine-tune how openpilot drives."),
|
||||
"manage_title": tr_noop("Advanced Settings"),
|
||||
"manage_desc": tr_noop("Adjust steering response, torque controller behavior, and auto-tuning controls."),
|
||||
"manage_label": tr_noop("Configure"),
|
||||
"disabled_label": tr_noop("Enable First"),
|
||||
"panel": "advanced_lateral",
|
||||
"get_state": lambda: self._params.get_bool("AdvancedLateralTune"),
|
||||
"set_state": lambda x: self._params.put_bool("AdvancedLateralTune", x),
|
||||
"icon": "toggle_icons/icon_advanced_lateral_tune.png",
|
||||
"color": "#597497",
|
||||
},
|
||||
{
|
||||
"title": tr_noop("Lateral Tuning"),
|
||||
"desc": tr_noop("Miscellaneous steering control changes such as turn desires and NNFF modes."),
|
||||
"manage_title": tr_noop("Lateral Settings"),
|
||||
"manage_desc": tr_noop("Open turn-intent and neural-network feedforward controls."),
|
||||
"manage_label": tr_noop("Configure"),
|
||||
"disabled_label": tr_noop("Enable First"),
|
||||
"panel": "lateral_tune",
|
||||
"get_state": lambda: self._params.get_bool("LateralTune"),
|
||||
"set_state": lambda x: self._params.put_bool("LateralTune", x),
|
||||
"icon": "toggle_icons/icon_lateral_tune.png",
|
||||
"color": "#597497",
|
||||
},
|
||||
], {
|
||||
self._sub_panels = {
|
||||
"advanced_lateral": StarPilotAdvancedLateralLayout(),
|
||||
"lateral_tune": StarPilotLateralTuneLayout(),
|
||||
})
|
||||
}
|
||||
self._wire_sub_panels()
|
||||
self._build_view()
|
||||
|
||||
self._section_tabs = TabbedSectionHost([
|
||||
TabSectionSpec("steering", "Steering", steering_panel),
|
||||
TabSectionSpec("lane", "Lane", StarPilotLaneChangesLayout()),
|
||||
TabSectionSpec("tune", "Tune", tune_panel),
|
||||
])
|
||||
def _build_view(self):
|
||||
tab_defs = [
|
||||
{"id": "steering", "title": tr_noop("Steering"), "subtitle": tr_noop("Steering modes")},
|
||||
{"id": "lane", "title": tr_noop("Lane"), "subtitle": tr_noop("Lane changes")},
|
||||
{"id": "tune", "title": tr_noop("Tune"), "subtitle": tr_noop("Advanced controls")},
|
||||
]
|
||||
|
||||
def set_navigate_callback(self, callback):
|
||||
self._section_tabs.set_navigate_callback(callback)
|
||||
sections = [
|
||||
# ── Steering tab ──
|
||||
SettingSection(tr_noop("Steering Modes"), [
|
||||
SettingRow("AlwaysOnLateral", "toggle", tr_noop("Always On Lateral"),
|
||||
subtitle=tr_noop("Keep lateral control active even without openpilot engaged."),
|
||||
get_state=lambda: self._params.get_bool("AlwaysOnLateral"),
|
||||
set_state=lambda s: _confirm_reboot_toggle(self._params, "AlwaysOnLateral", s)),
|
||||
SettingRow("AlwaysOnLateralLKAS", "toggle", tr_noop("Enable With LKAS"),
|
||||
subtitle="",
|
||||
get_state=lambda: self._params.get_bool("AlwaysOnLateralLKAS"),
|
||||
set_state=lambda s: self._params.put_bool("AlwaysOnLateralLKAS", s),
|
||||
visible=lambda: self._params.get_bool("AlwaysOnLateral") and starpilot_state.car_state.lkasAllowedForAOL),
|
||||
SettingRow("PauseAOLOnBrake", "value", tr_noop("Pause Below"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_int('PauseAOLOnBrake')} mph",
|
||||
on_click=lambda: self._show_slider("PauseAOLOnBrake", 0, 100, unit=" mph"),
|
||||
visible=lambda: self._params.get_bool("AlwaysOnLateral")),
|
||||
SettingRow("QOLLateral", "toggle", tr_noop("Quality of Life"),
|
||||
subtitle="",
|
||||
get_state=lambda: self._params.get_bool("QOLLateral"),
|
||||
set_state=lambda s: self._params.put_bool("QOLLateral", s)),
|
||||
SettingRow("PauseLateralSpeed", "value", tr_noop("Pause Steering Below"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_int('PauseLateralSpeed')} mph",
|
||||
on_click=lambda: self._show_slider("PauseLateralSpeed", 0, 100, unit=" mph"),
|
||||
visible=lambda: self._params.get_bool("QOLLateral")),
|
||||
], tab_key="steering", row_height=UTILITY_ROW_HEIGHT),
|
||||
|
||||
def set_back_callback(self, callback):
|
||||
self._section_tabs.set_back_callback(callback)
|
||||
# ── Lane tab ──
|
||||
SettingSection("", [
|
||||
SettingRow("LaneChanges", "toggle", tr_noop("Lane Changes"),
|
||||
subtitle="",
|
||||
get_state=lambda: self._params.get_bool("LaneChanges"),
|
||||
set_state=lambda s: self._params.put_bool("LaneChanges", s)),
|
||||
SettingRow("NudgelessLaneChange", "toggle", tr_noop("Automatic Lane Changes"),
|
||||
subtitle="",
|
||||
get_state=lambda: self._params.get_bool("NudgelessLaneChange"),
|
||||
set_state=lambda s: self._params.put_bool("NudgelessLaneChange", s),
|
||||
visible=lambda: self._params.get_bool("LaneChanges")),
|
||||
SettingRow("LaneChangeTime", "value", tr_noop("Lane Change Delay"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_float('LaneChangeTime'):.1f}s",
|
||||
on_click=lambda: self._show_slider("LaneChangeTime", 0.0, 5.0, step=0.1, unit="s", value_type="float"),
|
||||
visible=lambda: self._params.get_bool("LaneChanges") and self._params.get_bool("NudgelessLaneChange")),
|
||||
SettingRow("MinimumLaneChangeSpeed", "value", tr_noop("Min Lane Change Speed"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_int('MinimumLaneChangeSpeed')} mph",
|
||||
on_click=lambda: self._show_slider("MinimumLaneChangeSpeed", 0, 100, unit=" mph"),
|
||||
visible=lambda: self._params.get_bool("LaneChanges")),
|
||||
SettingRow("LaneDetectionWidth", "value", tr_noop("Minimum Lane Width"),
|
||||
subtitle="",
|
||||
get_value=lambda: f"{self._params.get_float('LaneDetectionWidth'):.1f} ft",
|
||||
on_click=lambda: self._show_slider("LaneDetectionWidth", 0.0, 15.0, step=0.1, unit=" ft", value_type="float"),
|
||||
visible=lambda: self._params.get_bool("LaneChanges") and self._params.get_bool("NudgelessLaneChange")),
|
||||
SettingRow("OneLaneChange", "toggle", tr_noop("One Lane Change Per Signal"),
|
||||
subtitle="",
|
||||
get_state=lambda: self._params.get_bool("OneLaneChange"),
|
||||
set_state=lambda s: self._params.put_bool("OneLaneChange", s),
|
||||
visible=lambda: self._params.get_bool("LaneChanges")),
|
||||
SettingRow("LaneChangeSmoothing", "value", tr_noop("Lane Change Smoothing"),
|
||||
subtitle=tr_noop("How smoothly openpilot commits to a lane change. 10 is stock; lower values produce a gentler, more gradual maneuver."),
|
||||
get_value=lambda: f"{self._params.get_int('LaneChangeSmoothing')}",
|
||||
on_click=self._show_modal_pace_selector,
|
||||
visible=lambda: self._params.get_bool("LaneChanges")),
|
||||
], tab_key="lane", row_height=UTILITY_ROW_HEIGHT),
|
||||
|
||||
def _render(self, rect):
|
||||
self._section_tabs.render(rect)
|
||||
# ── Tune tab ──
|
||||
SettingSection(tr_noop("Advanced Lateral Tuning"), [
|
||||
SettingRow("AdvancedLateralTune", "toggle", tr_noop("Advanced Lateral Tuning"),
|
||||
subtitle=tr_noop("Advanced steering control changes to fine-tune how openpilot drives."),
|
||||
get_state=lambda: self._params.get_bool("AdvancedLateralTune"),
|
||||
set_state=lambda s: self._params.put_bool("AdvancedLateralTune", s)),
|
||||
SettingRow("AdvancedConfigure", "value", tr_noop("Configure"),
|
||||
subtitle=tr_noop("Adjust steering response, torque controller behavior, and auto-tuning controls."),
|
||||
get_value=lambda: tr_noop("Settings"),
|
||||
navigate_to="advanced_lateral",
|
||||
enabled=lambda: self._params.get_bool("AdvancedLateralTune"),
|
||||
disabled_label=tr_noop("Enable First")),
|
||||
], tab_key="tune", row_height=UTILITY_ROW_HEIGHT),
|
||||
SettingSection(tr_noop("Lateral Tuning"), [
|
||||
SettingRow("LateralTune", "toggle", tr_noop("Lateral Tuning"),
|
||||
subtitle=tr_noop("Miscellaneous steering control changes such as turn desires and NNFF modes."),
|
||||
get_state=lambda: self._params.get_bool("LateralTune"),
|
||||
set_state=lambda s: self._params.put_bool("LateralTune", s)),
|
||||
SettingRow("TurnDesires", "toggle", tr_noop("Force Turn Desires Below Lane Change Speed"),
|
||||
subtitle=tr_noop("Allow openpilot to follow turn intent below the minimum lane change speed when signaling."),
|
||||
get_state=lambda: self._params.get_bool("TurnDesires"),
|
||||
set_state=lambda s: self._params.put_bool("TurnDesires", s),
|
||||
visible=lambda: self._params.get_bool("LateralTune")),
|
||||
SettingRow("NNFF", "toggle", tr_noop("Neural Network Feedforward (NNFF)"),
|
||||
subtitle=tr_noop("Use the full neural-network feedforward steering controller when available."),
|
||||
get_state=lambda: self._params.get_bool("NNFF"),
|
||||
set_state=lambda s: (self._params.put_bool("NNFF", s), s and self._params.put_bool("NNFFLite", False)),
|
||||
visible=lambda: self._params.get_bool("LateralTune") and starpilot_state.car_state.hasNNFFLog and not starpilot_state.car_state.isAngleCar),
|
||||
SettingRow("NNFFLite", "toggle", tr_noop("Neural Network Feedforward (NNFF) Lite"),
|
||||
subtitle=tr_noop("Use the lightweight NNFF steering logic when the full model is off."),
|
||||
get_state=lambda: self._params.get_bool("NNFFLite"),
|
||||
set_state=lambda s: _confirm_reboot_toggle(self._params, "NNFFLite", s),
|
||||
visible=lambda: self._params.get_bool("LateralTune") and not self._params.get_bool("NNFF") and not starpilot_state.car_state.isAngleCar),
|
||||
], tab_key="tune", row_height=UTILITY_ROW_HEIGHT),
|
||||
]
|
||||
|
||||
def set_current_sub_panel(self, sub_panel: str):
|
||||
self._section_tabs.set_current_sub_panel(sub_panel)
|
||||
self._manager_view = AetherSettingsView(
|
||||
self, sections,
|
||||
header_title=tr_noop("Steering"),
|
||||
header_subtitle=tr_noop("Fine-tune lateral control, lane changes, and steering behavior."),
|
||||
tab_defs=tab_defs,
|
||||
panel_style=PANEL_STYLE,
|
||||
)
|
||||
|
||||
def show_event(self):
|
||||
self._section_tabs.show_event()
|
||||
|
||||
def hide_event(self):
|
||||
self._section_tabs.hide_event()
|
||||
def _show_modal_pace_selector(self):
|
||||
def on_close(res, val):
|
||||
if res == DialogResult.CONFIRM:
|
||||
self._params.put_int("LaneChangeSmoothing", int(val))
|
||||
current = self._params.get_int("LaneChangeSmoothing") if self._params.get_int("LaneChangeSmoothing") > 0 else 10
|
||||
gui_app.set_modal_overlay(AetherSliderDialog(tr("Lane Change Smoothing"), 1, 10, 1, current, on_close, color="#597497"))
|
||||
|
||||
@@ -102,8 +102,11 @@ class AetherSettingsView(Widget):
|
||||
|
||||
def __init__(self, controller: StarPilotPanel, sections: list[SettingSection],
|
||||
*, header_title: str = "", header_subtitle: str = "",
|
||||
tab_defs: list[dict] | None = None):
|
||||
tab_defs: list[dict] | None = None,
|
||||
panel_style=None, fade_height: float = AETHER_LIST_METRICS.fade_height):
|
||||
super().__init__()
|
||||
self._panel_style = panel_style or PANEL_STYLE
|
||||
self._fade_height = fade_height
|
||||
self._controller = controller
|
||||
self._sections = sections
|
||||
self._header_title = header_title
|
||||
@@ -186,7 +189,7 @@ class AetherSettingsView(Widget):
|
||||
self.set_rect(rect)
|
||||
self._interactive_rects.clear()
|
||||
|
||||
frame, scroll_rect, content_width = init_list_panel(rect, PANEL_STYLE)
|
||||
frame, scroll_rect, content_width = init_list_panel(rect, self._panel_style)
|
||||
self._scroll_rect = scroll_rect
|
||||
|
||||
if self._has_header:
|
||||
@@ -206,7 +209,7 @@ class AetherSettingsView(Widget):
|
||||
self._scrollbar.render(self._scroll_rect, self._content_height, self._scroll_offset)
|
||||
|
||||
draw_list_scroll_fades(self._scroll_rect, self._content_height, self._scroll_offset,
|
||||
AetherListColors.PANEL_BG, fade_height=FADE_HEIGHT)
|
||||
AetherListColors.PANEL_BG, fade_height=self._fade_height)
|
||||
|
||||
def _draw_header(self, rect: rl.Rectangle):
|
||||
title = tr(self._header_title) if self._header_title else ""
|
||||
@@ -242,7 +245,7 @@ class AetherSettingsView(Widget):
|
||||
i += 2
|
||||
else:
|
||||
i += 1
|
||||
total += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
total += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP if section.title else 0.0
|
||||
total += row_h
|
||||
total += SECTION_GAP
|
||||
return max(0.0, total - SECTION_GAP) if total > 0 else 0.0
|
||||
@@ -250,9 +253,8 @@ class AetherSettingsView(Widget):
|
||||
def _draw_tabs(self, y: float, x: float, width: float) -> float:
|
||||
if not self._tab_defs:
|
||||
return y
|
||||
content_w = width - AETHER_LIST_METRICS.content_right_gutter
|
||||
n = len(self._tab_defs)
|
||||
tab_w = (content_w - self.TAB_GAP * max(0, n - 1)) / max(1, n)
|
||||
tab_w = (width - self.TAB_GAP * max(0, n - 1)) / max(1, n)
|
||||
for i, tab in enumerate(self._tab_defs):
|
||||
tab_rect = rl.Rectangle(x + i * (tab_w + self.TAB_GAP), y, tab_w, self.TAB_HEIGHT)
|
||||
target_id = f"tab:{tab['id']}"
|
||||
@@ -267,15 +269,20 @@ class AetherSettingsView(Widget):
|
||||
title_size=24,
|
||||
subtitle_size=17,
|
||||
show_underline=True,
|
||||
style=PANEL_STYLE,
|
||||
style=self._panel_style,
|
||||
)
|
||||
return y + self.TAB_HEIGHT + self.TAB_BOTTOM_GAP
|
||||
|
||||
def _has_subsequent_visible(self, start_idx: int, sections: list[SettingSection]) -> bool:
|
||||
for j in range(start_idx, len(sections)):
|
||||
if self._visible_rows(sections[j]):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _draw_scroll_content(self, rect: rl.Rectangle, width: float):
|
||||
y = rect.y + self._scroll_offset
|
||||
if self._tab_defs:
|
||||
y = self._draw_tabs(y, rect.x, width)
|
||||
content_w = width - AETHER_LIST_METRICS.content_right_gutter
|
||||
active = self._active_sections()
|
||||
i = 0
|
||||
while i < len(active):
|
||||
@@ -287,55 +294,59 @@ class AetherSettingsView(Widget):
|
||||
if section.column_pair and i + 1 < len(active) and active[i + 1].column_pair == section.column_pair:
|
||||
right_section = active[i + 1]
|
||||
right_rows = self._visible_rows(right_section)
|
||||
col_w = (content_w - self.COLUMN_GAP) / 2
|
||||
col_w = (width - self.COLUMN_GAP) / 2
|
||||
section_h = len(visible_rows) * section.row_height
|
||||
right_h = len(right_rows) * right_section.row_height
|
||||
group_h = max(section_h, right_h)
|
||||
|
||||
draw_section_header(
|
||||
rl.Rectangle(rect.x, y, col_w, SECTION_HEADER_HEIGHT),
|
||||
tr(section.title), style=PANEL_STYLE,
|
||||
tr(section.title), style=self._panel_style,
|
||||
)
|
||||
draw_section_header(
|
||||
rl.Rectangle(rect.x + col_w + self.COLUMN_GAP, y, col_w, SECTION_HEADER_HEIGHT),
|
||||
tr(right_section.title), style=PANEL_STYLE,
|
||||
tr(right_section.title), style=self._panel_style,
|
||||
)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
|
||||
left_group = rl.Rectangle(rect.x, y, col_w, section_h)
|
||||
right_group = rl.Rectangle(rect.x + col_w + self.COLUMN_GAP, y, col_w, right_h)
|
||||
draw_list_group_shell(left_group, style=PANEL_STYLE)
|
||||
draw_list_group_shell(right_group, style=PANEL_STYLE)
|
||||
draw_list_group_shell(left_group, style=self._panel_style)
|
||||
draw_list_group_shell(right_group, style=self._panel_style)
|
||||
|
||||
for j, row in enumerate(visible_rows):
|
||||
self._draw_row(rl.Rectangle(rect.x, y + j * section.row_height, col_w, section.row_height), row, is_last=(j == len(visible_rows) - 1))
|
||||
for j, row in enumerate(right_rows):
|
||||
self._draw_row(rl.Rectangle(rect.x + col_w + self.COLUMN_GAP, y + j * right_section.row_height, col_w, right_section.row_height), row, is_last=(j == len(right_rows) - 1))
|
||||
|
||||
y += group_h + SECTION_GAP
|
||||
y += group_h
|
||||
if self._has_subsequent_visible(i + 2, active):
|
||||
y += SECTION_GAP
|
||||
i += 2
|
||||
else:
|
||||
y = self._draw_section(y, rect.x, width, section, visible_rows)
|
||||
if self._has_subsequent_visible(i + 1, active):
|
||||
y += SECTION_GAP
|
||||
i += 1
|
||||
|
||||
def _draw_section(self, y: float, x: float, width: float,
|
||||
section: SettingSection, rows: list[SettingRow]) -> float:
|
||||
content_w = width - AETHER_LIST_METRICS.content_right_gutter
|
||||
draw_section_header(
|
||||
rl.Rectangle(x, y, content_w, SECTION_HEADER_HEIGHT),
|
||||
tr(section.title),
|
||||
style=PANEL_STYLE,
|
||||
)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
if section.title:
|
||||
draw_section_header(
|
||||
rl.Rectangle(x, y, width, SECTION_HEADER_HEIGHT),
|
||||
tr(section.title),
|
||||
style=self._panel_style,
|
||||
)
|
||||
y += SECTION_HEADER_HEIGHT + SECTION_HEADER_GAP
|
||||
|
||||
group_rect = rl.Rectangle(x, y, content_w, len(rows) * section.row_height)
|
||||
draw_list_group_shell(group_rect, style=PANEL_STYLE)
|
||||
group_rect = rl.Rectangle(x, y, width, len(rows) * section.row_height)
|
||||
draw_list_group_shell(group_rect, style=self._panel_style)
|
||||
|
||||
for i, row in enumerate(rows):
|
||||
row_rect = rl.Rectangle(x, y + i * section.row_height, content_w, section.row_height)
|
||||
row_rect = rl.Rectangle(x, y + i * section.row_height, width, section.row_height)
|
||||
self._draw_row(row_rect, row, is_last=(i == len(rows) - 1))
|
||||
|
||||
return y + group_rect.height + SECTION_GAP
|
||||
return y + group_rect.height
|
||||
|
||||
def _draw_row(self, rect: rl.Rectangle, row: SettingRow, is_last: bool):
|
||||
target_id = f"{row.type}:{row.id}"
|
||||
@@ -356,7 +367,7 @@ class AetherSettingsView(Widget):
|
||||
pressed=pressed,
|
||||
is_last=is_last,
|
||||
show_chevron=False,
|
||||
style=PANEL_STYLE,
|
||||
style=self._panel_style,
|
||||
)
|
||||
elif row.type == "value":
|
||||
value_text = row.get_value() if row.get_value else ""
|
||||
@@ -370,13 +381,13 @@ class AetherSettingsView(Widget):
|
||||
pressed=pressed,
|
||||
is_last=is_last,
|
||||
show_chevron=row.on_click is not None,
|
||||
style=PANEL_STYLE,
|
||||
style=self._panel_style,
|
||||
)
|
||||
elif row.type == "action":
|
||||
action_fill = AetherListColors.DANGER_SOFT if row.action_danger else PANEL_STYLE.current_fill
|
||||
action_fill = AetherListColors.DANGER_SOFT if row.action_danger else self._panel_style.current_fill
|
||||
action_border = (rl.Color(AetherListColors.DANGER.r, AetherListColors.DANGER.g,
|
||||
AetherListColors.DANGER.b, 70)
|
||||
if row.action_danger else PANEL_STYLE.current_border)
|
||||
if row.action_danger else self._panel_style.current_border)
|
||||
action_text_color = AetherListColors.DANGER if row.action_danger else AetherListColors.HEADER
|
||||
draw_selection_list_row(
|
||||
rect,
|
||||
@@ -390,7 +401,7 @@ class AetherSettingsView(Widget):
|
||||
action_text_color=action_text_color,
|
||||
action_fill=action_fill,
|
||||
action_border=action_border,
|
||||
row_separator=PANEL_STYLE.divider_color,
|
||||
row_separator=self._panel_style.divider_color,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user