diff --git a/selfdrive/ui/layouts/main.py b/selfdrive/ui/layouts/main.py index 6cfecc63bb..a3081143f4 100644 --- a/selfdrive/ui/layouts/main.py +++ b/selfdrive/ui/layouts/main.py @@ -4,7 +4,7 @@ import cereal.messaging as messaging from openpilot.selfdrive.ui.layouts.sidebar import Sidebar, SIDEBAR_WIDTH from openpilot.selfdrive.ui.layouts.home import HomeLayout from openpilot.selfdrive.ui.layouts.settings.settings import SettingsLayout, PanelType -from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.selfdrive.ui.ui_state import device, ui_state from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView from openpilot.system.ui.lib.widget import Widget @@ -44,6 +44,7 @@ class MainLayout(Widget): self._layouts[MainState.HOME]._setup_widget.set_open_settings_callback(lambda: self.open_settings(PanelType.FIREHOSE)) self._layouts[MainState.SETTINGS].set_callbacks(on_close=self._set_mode_for_state) self._layouts[MainState.ONROAD].set_callbacks(on_click=self._on_onroad_clicked) + device.add_interactive_timeout_callback(self._set_mode_for_state) def _update_layout_rects(self): self._sidebar_rect = rl.Rectangle(self._rect.x, self._rect.y, SIDEBAR_WIDTH, self._rect.height) @@ -59,8 +60,10 @@ class MainLayout(Widget): def _set_mode_for_state(self): if ui_state.started: + # Don't hide sidebar from interactive timeout + if self._current_mode != MainState.ONROAD: + self._sidebar.set_visible(False) self._current_mode = MainState.ONROAD - self._sidebar.set_visible(False) else: self._current_mode = MainState.HOME self._sidebar.set_visible(True) diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index 9e0afa6775..3738ea6d5d 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -1,4 +1,6 @@ import pyray as rl +import time +from collections.abc import Callable from enum import Enum from cereal import messaging, log from openpilot.common.params import Params, UnknownKeyName @@ -76,6 +78,7 @@ class UIState: self.sm.update(0) self._update_state() self._update_status() + device.update() def _update_state(self) -> None: # Handle panda states updates @@ -133,5 +136,36 @@ class UIState: self.is_metric = False +class Device: + def __init__(self): + self._ignition = False + self._interaction_time: float = 0.0 + self._interactive_timeout_callbacks: list[Callable] = [] + self._prev_timed_out = False + self.reset_interactive_timeout() + + def reset_interactive_timeout(self, timeout: int = -1) -> None: + if timeout == -1: + timeout = 10 if ui_state.ignition else 30 + self._interaction_time = time.monotonic() + timeout + + def add_interactive_timeout_callback(self, callback: Callable): + self._interactive_timeout_callbacks.append(callback) + + def update(self): + # Handle interactive timeout + ignition_just_turned_off = not ui_state.ignition and self._ignition + self._ignition = ui_state.ignition + + interaction_timeout = time.monotonic() > self._interaction_time + if ignition_just_turned_off or rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT): + self.reset_interactive_timeout() + elif interaction_timeout and not self._prev_timed_out: + for callback in self._interactive_timeout_callbacks: + callback() + self._prev_timed_out = interaction_timeout + + # Global instance ui_state = UIState() +device = Device()