raylib: generic click callback (#36166)

* not to be used outside

* same

* rm

* fix that

* another fix

* ehh probably better to still have

* optional
pull/36121/head^2
Shane Smiskol 2 days ago committed by GitHub
parent 086e33dd6e
commit b622e3e0a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      selfdrive/ui/onroad/augmented_road_view.py
  2. 33
      system/ui/widgets/__init__.py
  3. 11
      system/ui/widgets/button.py

@ -102,10 +102,13 @@ class AugmentedRoadView(CameraView):
# Handle click events if no HUD interaction occurred
if not self._hud_renderer.handle_mouse_event():
if self._click_callback and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
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_release(self, _):
pass
def _draw_border(self, rect: rl.Rectangle):
border_color = BORDER_COLORS.get(ui_state.status, BORDER_COLORS[UIStatus.DISENGAGED])
rl.draw_rectangle_lines_ex(rect, UI_BORDER_SIZE, border_color)

@ -15,12 +15,13 @@ class Widget(abc.ABC):
def __init__(self):
self._rect: rl.Rectangle = rl.Rectangle(0, 0, 0, 0)
self._parent_rect: rl.Rectangle = rl.Rectangle(0, 0, 0, 0)
self._is_pressed = [False] * MAX_TOUCH_SLOTS
self.__is_pressed = [False] * MAX_TOUCH_SLOTS
# if current mouse/touch down started within the widget's rectangle
self._tracking_is_pressed = [False] * MAX_TOUCH_SLOTS
self.__tracking_is_pressed = [False] * MAX_TOUCH_SLOTS
self._enabled: bool | Callable[[], bool] = True
self._is_visible: bool | Callable[[], bool] = True
self._touch_valid_callback: Callable[[], bool] | None = None
self._click_callback: Callable[[], None] | None = None
self._multi_touch = False
@property
@ -40,7 +41,7 @@ class Widget(abc.ABC):
@property
def is_pressed(self) -> bool:
return any(self._is_pressed)
return any(self.__is_pressed)
@property
def enabled(self) -> bool:
@ -56,6 +57,10 @@ class Widget(abc.ABC):
def set_visible(self, visible: bool | Callable[[], bool]) -> None:
self._is_visible = visible
def set_click_callback(self, click_callback: Callable[[], None] | None) -> None:
"""Set a callback to be called when the widget is clicked."""
self._click_callback = click_callback
def set_touch_valid_callback(self, touch_callback: Callable[[], bool]) -> None:
"""Set a callback to determine if the widget can be clicked."""
self._touch_valid_callback = touch_callback
@ -91,28 +96,28 @@ 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._is_pressed[mouse_event.slot] = True
self._tracking_is_pressed[mouse_event.slot] = True
self.__is_pressed[mouse_event.slot] = True
self.__tracking_is_pressed[mouse_event.slot] = True
# Callback such as scroll panel signifies user is scrolling
elif not self._touch_valid():
self._is_pressed[mouse_event.slot] = False
self._tracking_is_pressed[mouse_event.slot] = False
self.__is_pressed[mouse_event.slot] = False
self.__tracking_is_pressed[mouse_event.slot] = False
elif mouse_event.left_released:
if self._is_pressed[mouse_event.slot] and rl.check_collision_point_rec(mouse_event.pos, self._rect):
if self.__is_pressed[mouse_event.slot] and rl.check_collision_point_rec(mouse_event.pos, self._rect):
self._handle_mouse_release(mouse_event.pos)
self._is_pressed[mouse_event.slot] = False
self._tracking_is_pressed[mouse_event.slot] = False
self.__is_pressed[mouse_event.slot] = False
self.__tracking_is_pressed[mouse_event.slot] = False
# Mouse/touch is still within our rect
elif rl.check_collision_point_rec(mouse_event.pos, self._rect):
if self._tracking_is_pressed[mouse_event.slot]:
self._is_pressed[mouse_event.slot] = True
if self.__tracking_is_pressed[mouse_event.slot]:
self.__is_pressed[mouse_event.slot] = True
# Mouse/touch left our rect but may come back into focus later
elif not rl.check_collision_point_rec(mouse_event.pos, self._rect):
self._is_pressed[mouse_event.slot] = False
self.__is_pressed[mouse_event.slot] = False
return ret
@ -128,6 +133,8 @@ class Widget(abc.ABC):
def _handle_mouse_release(self, mouse_pos: MousePos) -> bool:
"""Optionally handle mouse release events."""
if self._click_callback:
self._click_callback()
return False
def show_event(self):

@ -165,7 +165,7 @@ def gui_button(
class Button(Widget):
def __init__(self,
text: str,
click_callback: Callable[[], None] = None,
click_callback: Callable[[], None] | None = None,
font_size: int = DEFAULT_BUTTON_FONT_SIZE,
font_weight: FontWeight = FontWeight.MEDIUM,
button_style: ButtonStyle = ButtonStyle.NORMAL,
@ -190,10 +190,6 @@ class Button(Widget):
def set_text(self, text):
self._label.set_text(text)
def _handle_mouse_release(self, mouse_pos: MousePos):
if self._click_callback and self.enabled:
self._click_callback()
def _update_state(self):
if self.enabled:
self._label.set_text_color(BUTTON_TEXT_COLOR[self._button_style])
@ -215,7 +211,7 @@ class ButtonRadio(Button):
def __init__(self,
text: str,
icon,
click_callback: Callable[[], None] = None,
click_callback: Callable[[], None] | None = None,
font_size: int = DEFAULT_BUTTON_FONT_SIZE,
text_alignment: TextAlignment = TextAlignment.LEFT,
border_radius: int = 10,
@ -230,9 +226,8 @@ class ButtonRadio(Button):
self.selected = False
def _handle_mouse_release(self, mouse_pos: MousePos):
super()._handle_mouse_release(mouse_pos)
self.selected = not self.selected
if self._click_callback:
self._click_callback()
def _update_state(self):
if self.selected:

Loading…
Cancel
Save