mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-03 22:53:44 +08:00
132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
import time
|
|
from collections.abc import Callable
|
|
|
|
import pyray as rl
|
|
|
|
from openpilot.selfdrive.ui.ui_state import ui_state
|
|
from openpilot.selfdrive.ui.lib.starpilot_status import (
|
|
ENGAGED_COLOR, EXPERIMENTAL_COLOR, TRAFFIC_COLOR,
|
|
)
|
|
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
|
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
|
from openpilot.system.ui.widgets import Widget
|
|
|
|
|
|
class StoppedTimerWidget(Widget):
|
|
SHOW_AFTER_SECONDS = 60
|
|
|
|
def __init__(self, in_reverse: Callable[[], bool] | None = None):
|
|
super().__init__()
|
|
self.set_enabled(False)
|
|
self._in_reverse = in_reverse or (lambda: False)
|
|
self._font_bold = gui_app.font(FontWeight.BOLD)
|
|
self._font_normal = gui_app.font(FontWeight.NORMAL)
|
|
self._standstill_started_at: float | None = None
|
|
self._started_frame = -1
|
|
self._duration = 0
|
|
|
|
@property
|
|
def is_visible(self) -> bool:
|
|
return self._update_timer() > 0
|
|
|
|
@property
|
|
def replaces_current_speed(self) -> bool:
|
|
return self.is_visible
|
|
|
|
def _update_timer(self) -> int:
|
|
started_frame = getattr(ui_state, "started_frame", 0)
|
|
if started_frame != self._started_frame:
|
|
self._started_frame = started_frame
|
|
self._reset_timer()
|
|
|
|
params = ui_state.ui_params
|
|
if (not ui_state.started or
|
|
not params.get_bool("QOLVisuals") or
|
|
not params.get_bool("StoppedTimer") or
|
|
not ui_state.sm.valid.get("carState", False)):
|
|
self._reset_timer()
|
|
return 0
|
|
|
|
if self._in_reverse():
|
|
self._reset_timer()
|
|
return 0
|
|
|
|
try:
|
|
if ui_state.sm.recv_frame["carState"] < started_frame:
|
|
self._reset_timer()
|
|
return 0
|
|
except (AttributeError, KeyError, TypeError):
|
|
pass
|
|
|
|
if not getattr(ui_state.sm["carState"], "standstill", False):
|
|
self._reset_timer()
|
|
return 0
|
|
|
|
now = time.monotonic()
|
|
if self._standstill_started_at is None:
|
|
self._standstill_started_at = now
|
|
|
|
if now - getattr(ui_state, "started_time", 0.0) < self.SHOW_AFTER_SECONDS:
|
|
self._duration = 0
|
|
return 0
|
|
|
|
self._duration = max(0, int(now - self._standstill_started_at))
|
|
return self._duration
|
|
|
|
def _reset_timer(self) -> None:
|
|
self._standstill_started_at = None
|
|
self._duration = 0
|
|
|
|
@staticmethod
|
|
def _format_duration_text(duration: int) -> tuple[str, str]:
|
|
minutes = duration // 60
|
|
seconds = duration % 60
|
|
return (
|
|
f"{minutes} minute{'s' if minutes != 1 else ''}",
|
|
f"{seconds} second{'s' if seconds != 1 else ''}",
|
|
)
|
|
|
|
def _render(self, rect: rl.Rectangle) -> None:
|
|
duration = self._duration
|
|
minute_text, second_text = self._format_duration_text(duration)
|
|
|
|
minute_size = measure_text_cached(self._font_bold, minute_text, 176)
|
|
second_size = measure_text_cached(self._font_normal, second_text, 66)
|
|
|
|
if duration < 150:
|
|
transition = (duration - 60) / 90.0
|
|
duration_color = self._blend_colors(ENGAGED_COLOR, EXPERIMENTAL_COLOR, transition)
|
|
elif duration < 300:
|
|
transition = (duration - 150) / 150.0
|
|
duration_color = self._blend_colors(EXPERIMENTAL_COLOR, TRAFFIC_COLOR, transition)
|
|
else:
|
|
duration_color = TRAFFIC_COLOR
|
|
|
|
center_x = rect.x + rect.width / 2
|
|
rl.draw_text_ex(
|
|
self._font_bold,
|
|
minute_text,
|
|
rl.Vector2(center_x - minute_size.x / 2, rect.y + 210 - minute_size.y),
|
|
176,
|
|
0,
|
|
duration_color,
|
|
)
|
|
rl.draw_text_ex(
|
|
self._font_normal,
|
|
second_text,
|
|
rl.Vector2(center_x - second_size.x / 2, rect.y + 290 - second_size.y),
|
|
66,
|
|
0,
|
|
rl.Color(255, 255, 255, 255),
|
|
)
|
|
|
|
@staticmethod
|
|
def _blend_colors(start: rl.Color, end: rl.Color, transition: float) -> rl.Color:
|
|
transition = min(max(transition, 0.0), 1.0)
|
|
return rl.Color(
|
|
int(start.r + transition * (end.r - start.r)),
|
|
int(start.g + transition * (end.g - start.g)),
|
|
int(start.b + transition * (end.b - start.b)),
|
|
255,
|
|
)
|