raylib: fix lost onroad tap events (#36211)

* debug

* see it's good to have abstraction

* clean up

* fine

* wtf do you mean mypy? how can you not coerce this?
pull/36185/merge
Shane Smiskol 1 day ago committed by GitHub
parent ed185e90f6
commit 2feddf32b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      selfdrive/ui/layouts/main.py
  2. 16
      selfdrive/ui/onroad/augmented_road_view.py
  3. 25
      selfdrive/ui/onroad/exp_button.py
  4. 6
      selfdrive/ui/onroad/hud_renderer.py
  5. 5
      system/ui/widgets/__init__.py

@ -50,7 +50,7 @@ class MainLayout(Widget):
on_flag=self._on_bookmark_clicked)
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)
self._layouts[MainState.ONROAD].set_click_callback(self._on_onroad_clicked)
device.add_interactive_timeout_callback(self._set_mode_for_state)
def _update_layout_rects(self):

@ -1,6 +1,5 @@
import numpy as np
import pyray as rl
from collections.abc import Callable
from cereal import log
from msgq.visionipc import VisionStreamType
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus, UI_BORDER_SIZE
@ -49,12 +48,6 @@ class AugmentedRoadView(CameraView):
self.alert_renderer = AlertRenderer()
self.driver_state_renderer = DriverStateRenderer()
# Callbacks
self._click_callback: Callable | None = None
def set_callbacks(self, on_click: Callable | None = None):
self._click_callback = on_click
def _render(self, rect):
# Only render when system is started to avoid invalid data access
if not ui_state.started:
@ -100,13 +93,12 @@ class AugmentedRoadView(CameraView):
# End clipping region
rl.end_scissor_mode()
# Handle click events if no HUD interaction occurred
if not self._hud_renderer.handle_mouse_event():
if self._click_callback is not None and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
if rl.check_collision_point_rec(rl.get_mouse_position(), self._content_rect):
self._click_callback()
def _handle_mouse_press(self, _):
if not self._hud_renderer.user_interacting() and self._click_callback is not None:
self._click_callback()
def _handle_mouse_release(self, _):
# We only call click callback on press if not interacting with HUD
pass
def _draw_border(self, rect: rl.Rectangle):

@ -32,26 +32,21 @@ class ExpButton(Widget):
self._experimental_mode = selfdrive_state.experimentalMode
self._engageable = selfdrive_state.engageable or selfdrive_state.enabled
def handle_mouse_event(self) -> bool:
if rl.check_collision_point_rec(rl.get_mouse_position(), self._rect):
if (rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT) and
self._is_toggle_allowed()):
new_mode = not self._experimental_mode
self._params.put_bool("ExperimentalMode", new_mode)
# Hold new state temporarily
self._held_mode = new_mode
self._hold_end_time = time.monotonic() + self._hold_duration
return True
return False
def _handle_mouse_release(self, _):
super()._handle_mouse_release(_)
if self._is_toggle_allowed():
new_mode = not self._experimental_mode
self._params.put_bool("ExperimentalMode", new_mode)
# Hold new state temporarily
self._held_mode = new_mode
self._hold_end_time = time.monotonic() + self._hold_duration
def _render(self, rect: rl.Rectangle) -> None:
center_x = int(self._rect.x + self._rect.width // 2)
center_y = int(self._rect.y + self._rect.height // 2)
mouse_over = rl.check_collision_point_rec(rl.get_mouse_position(), self._rect)
mouse_down = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) and self.is_pressed
self._white_color.a = 180 if (mouse_down and mouse_over) or not self._engageable else 255
self._white_color.a = 180 if self.is_pressed or not self._engageable else 255
texture = self._txt_exp if self._held_or_actual_mode() else self._txt_wheel
rl.draw_circle(center_x, center_y, self._rect.width / 2, self._black_bg)

@ -69,7 +69,7 @@ class HudRenderer(Widget):
self._font_bold: rl.Font = gui_app.font(FontWeight.BOLD)
self._font_medium: rl.Font = gui_app.font(FontWeight.MEDIUM)
self._exp_button = ExpButton(UI_CONFIG.button_size, UI_CONFIG.wheel_icon_size)
self._exp_button: ExpButton = ExpButton(UI_CONFIG.button_size, UI_CONFIG.wheel_icon_size)
def _update_state(self) -> None:
"""Update HUD state based on car state and controls state."""
@ -120,8 +120,8 @@ class HudRenderer(Widget):
button_y = rect.y + UI_CONFIG.border_size
self._exp_button.render(rl.Rectangle(button_x, button_y, UI_CONFIG.button_size, UI_CONFIG.button_size))
def handle_mouse_event(self) -> bool:
return bool(self._exp_button.handle_mouse_event())
def user_interacting(self) -> bool:
return self._exp_button.is_pressed
def _draw_set_speed(self, rect: rl.Rectangle) -> None:
"""Draw the MAX speed indicator box."""

@ -96,6 +96,7 @@ class Widget(abc.ABC):
# Allows touch to leave the rect and come back in focus if mouse did not release
if mouse_event.left_pressed and self._touch_valid():
if rl.check_collision_point_rec(mouse_event.pos, self._rect):
self._handle_mouse_press(mouse_event.pos)
self.__is_pressed[mouse_event.slot] = True
self.__tracking_is_pressed[mouse_event.slot] = True
@ -131,6 +132,10 @@ class Widget(abc.ABC):
def _update_layout_rects(self) -> None:
"""Optionally update any layout rects on Widget rect change."""
def _handle_mouse_press(self, mouse_pos: MousePos) -> bool:
"""Optionally handle mouse press events."""
return False
def _handle_mouse_release(self, mouse_pos: MousePos) -> bool:
"""Optionally handle mouse release events."""
if self._click_callback:

Loading…
Cancel
Save