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 2 days 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) 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.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.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) device.add_interactive_timeout_callback(self._set_mode_for_state)
def _update_layout_rects(self): def _update_layout_rects(self):

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

@ -32,26 +32,21 @@ class ExpButton(Widget):
self._experimental_mode = selfdrive_state.experimentalMode self._experimental_mode = selfdrive_state.experimentalMode
self._engageable = selfdrive_state.engageable or selfdrive_state.enabled self._engageable = selfdrive_state.engageable or selfdrive_state.enabled
def handle_mouse_event(self) -> bool: def _handle_mouse_release(self, _):
if rl.check_collision_point_rec(rl.get_mouse_position(), self._rect): super()._handle_mouse_release(_)
if (rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT) and if self._is_toggle_allowed():
self._is_toggle_allowed()): new_mode = not self._experimental_mode
new_mode = not self._experimental_mode self._params.put_bool("ExperimentalMode", new_mode)
self._params.put_bool("ExperimentalMode", new_mode)
# Hold new state temporarily
# Hold new state temporarily self._held_mode = new_mode
self._held_mode = new_mode self._hold_end_time = time.monotonic() + self._hold_duration
self._hold_end_time = time.monotonic() + self._hold_duration
return True
return False
def _render(self, rect: rl.Rectangle) -> None: def _render(self, rect: rl.Rectangle) -> None:
center_x = int(self._rect.x + self._rect.width // 2) center_x = int(self._rect.x + self._rect.width // 2)
center_y = int(self._rect.y + self._rect.height // 2) center_y = int(self._rect.y + self._rect.height // 2)
mouse_over = rl.check_collision_point_rec(rl.get_mouse_position(), self._rect) self._white_color.a = 180 if self.is_pressed or not self._engageable else 255
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
texture = self._txt_exp if self._held_or_actual_mode() else self._txt_wheel 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) 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_bold: rl.Font = gui_app.font(FontWeight.BOLD)
self._font_medium: rl.Font = gui_app.font(FontWeight.MEDIUM) 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: def _update_state(self) -> None:
"""Update HUD state based on car state and controls state.""" """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 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)) self._exp_button.render(rl.Rectangle(button_x, button_y, UI_CONFIG.button_size, UI_CONFIG.button_size))
def handle_mouse_event(self) -> bool: def user_interacting(self) -> bool:
return bool(self._exp_button.handle_mouse_event()) return self._exp_button.is_pressed
def _draw_set_speed(self, rect: rl.Rectangle) -> None: def _draw_set_speed(self, rect: rl.Rectangle) -> None:
"""Draw the MAX speed indicator box.""" """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 # 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 mouse_event.left_pressed and self._touch_valid():
if rl.check_collision_point_rec(mouse_event.pos, self._rect): 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.__is_pressed[mouse_event.slot] = True
self.__tracking_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: def _update_layout_rects(self) -> None:
"""Optionally update any layout rects on Widget rect change.""" """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: def _handle_mouse_release(self, mouse_pos: MousePos) -> bool:
"""Optionally handle mouse release events.""" """Optionally handle mouse release events."""
if self._click_callback: if self._click_callback:

Loading…
Cancel
Save