Files
StarPilot/selfdrive/ui/lib/mode_banner.py
T
2026-07-20 21:34:47 -05:00

96 lines
3.8 KiB
Python

from enum import StrEnum
import pyray as rl
from openpilot.starpilot.common.experimental_state import requested_experimental_mode
class ModeBannerVariant(StrEnum):
CHILL = "chill"
EXPERIMENTAL = "experimental"
CONDITIONAL_EXPERIMENTAL = "conditional_experimental"
CONDITIONAL_CHILL = "conditional_chill"
def get_mode_banner_variant(params, params_memory=None) -> ModeBannerVariant:
if params.get_bool("SafeMode"):
return ModeBannerVariant.CHILL
if params.get_bool("ConditionalExperimental"):
return ModeBannerVariant.CONDITIONAL_EXPERIMENTAL
if params.get_bool("ConditionalChill"):
return ModeBannerVariant.CONDITIONAL_CHILL
if requested_experimental_mode(params, params_memory):
return ModeBannerVariant.EXPERIMENTAL
return ModeBannerVariant.CHILL
def _color(red: int, green: int, blue: int, alpha: int) -> rl.Color:
return rl.Color(red, green, blue, alpha)
def _lerp_color(start: rl.Color, end: rl.Color, progress: float, alpha: int) -> rl.Color:
progress = max(0.0, min(1.0, progress))
return rl.Color(
round(start.r + (end.r - start.r) * progress),
round(start.g + (end.g - start.g) * progress),
round(start.b + (end.b - start.b) * progress),
alpha,
)
def _conditional_colors(variant: ModeBannerVariant, alpha: int) -> tuple[rl.Color, rl.Color, rl.Color, rl.Color]:
blue = _color(35, 149, 255, alpha)
mint = _color(20, 255, 171, alpha)
orange = _color(255, 138, 22, alpha)
red = _color(219, 56, 34, alpha)
if variant == ModeBannerVariant.CONDITIONAL_EXPERIMENTAL:
return blue, mint, orange, red
return orange, red, blue, mint
def mode_banner_color(variant: ModeBannerVariant, progress: float, alpha: int = 255) -> rl.Color:
progress = max(0.0, min(1.0, progress))
if variant == ModeBannerVariant.CHILL:
return _lerp_color(_color(20, 255, 171, alpha), _color(35, 149, 255, alpha), progress, alpha)
if variant == ModeBannerVariant.EXPERIMENTAL:
return _lerp_color(_color(255, 155, 63, alpha), _color(219, 56, 34, alpha), progress, alpha)
dominant_start, dominant_end, target_start, target_end = _conditional_colors(variant, alpha)
if progress <= 0.58:
return _lerp_color(dominant_start, dominant_end, progress / 0.58, alpha)
if progress <= 0.80:
return _lerp_color(dominant_end, target_start, (progress - 0.58) / 0.22, alpha)
return _lerp_color(target_start, target_end, ((progress - 0.80) / 0.20) * 0.67, alpha)
def mode_atom_color(variant: ModeBannerVariant, progress: float, alpha: int = 255) -> rl.Color:
# The compact atom reads left-to-right as blue to mint in fixed Chill mode.
if variant == ModeBannerVariant.CHILL:
progress = 1.0 - progress
return mode_banner_color(variant, progress, alpha)
def draw_mode_banner_gradient(rect: rl.Rectangle, variant: ModeBannerVariant, alpha: int = 255) -> None:
if variant in (ModeBannerVariant.CHILL, ModeBannerVariant.EXPERIMENTAL):
rl.draw_rectangle_gradient_h(
int(rect.x), int(rect.y), int(rect.width), int(rect.height),
mode_banner_color(variant, 0.0, alpha), mode_banner_color(variant, 1.0, alpha),
)
return
transition_start = int(rect.x + rect.width * 0.58)
transition_end = int(rect.x + rect.width * 0.80)
right = int(rect.x + rect.width)
rl.draw_rectangle_gradient_h(
int(rect.x), int(rect.y), transition_start - int(rect.x), int(rect.height),
mode_banner_color(variant, 0.0, alpha), mode_banner_color(variant, 0.58, alpha),
)
rl.draw_rectangle_gradient_h(
transition_start, int(rect.y), transition_end - transition_start, int(rect.height),
mode_banner_color(variant, 0.58, alpha), mode_banner_color(variant, 0.80, alpha),
)
rl.draw_rectangle_gradient_h(
transition_end, int(rect.y), right - transition_end, int(rect.height),
mode_banner_color(variant, 0.80, alpha), mode_banner_color(variant, 1.0, alpha),
)